所以我在我的MVC应用程序中设置了一个自定义登录,似乎可以工作......
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(User model, string returnUrl)
{
if (ModelState.IsValid)
{
if (model.Login())
{
FormsAuthentication.SetAuthCookie(model.Username, true);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid email address or password.");
}
}
// If execution got this far, something failed, redisplay form
return View(model);
}
public class User
{
public bool Login()
{
var user = db.Users.FirstOrDefault(u => u.EmailAddress == EmailAddress);
if (user == null)
{
throw new ValidationException("User not found.");
}
else
{
// validates whether or not the password on the user record
// that was retrieved by the query matches the password entered at login
return Hashing.ValidatePassword(Password, user.Password);
}
}
}
不幸的是,它与默认的_LoginPartial.cshtml
视图(如下所示)之间存在一些冲突:
@model LoganMVC.Models.User
@if (Request.IsAuthenticated) {
<text>
Hello, @Html.ActionLink(User.Identity.Name, "Manage", "Account", new { User.Identity.Name })!
@using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) {
@Html.AntiForgeryToken()
<a href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
}
</text>
} else {
<ul>
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
ArgumentNullException突出显示此行......
您好,@ Html.ActionLink(User.Identity.Name,&#34; Manage&#34;,&#34; Account&#34;,new {User.Identity.Name})!
说...
值不能为null或为空。
很明显,不能为空或空的值为User.Identity.Name
,但不清楚的是,为什么IsAuthenticated
为真。这是表单身份验证,并且,只要软件知道(因为我杀死了调试服务器,关闭了解决方案并重新开始调试),应用程序从未运行过。
答案 0 :(得分:1)
好吧,我一直在抨击各种坚硬的表面,试图弄清楚这一点,并最终做到了。
在查看我最初得到的错误之后:
值不能为null或为空。
然后是
提供的类型为System.Web.Security.FormsIdentity&#39;标记为IsAuthenticated = true但没有Name的值。默认情况下,防伪系统要求所有经过身份验证的身份都具有唯一的名称。如果无法为此标识提供唯一的名称,请考虑将静态属性AntiForgeryConfig.AdditionalDataProvider设置为可为当前用户提供某种形式的唯一标识符的类型的实例。
修复相当简单。
首先,我最初将登录cookie设置为持续存在。这意味着当浏览器关闭时它不会被删除,也不会过期。虽然这不会导致Value cannot be null or empty
错误,但这是因为网站找到它并假设用户已经过身份验证。
<强> FIX 强>
为了解决这个问题,我只是从我的浏览器中清除了cookie,将cookie保持为假。这让我更专注于实际问题。
值不能为空或空
这个问题实际上没有我想象的那么复杂。当我开始仔细研究事物时,我注意到以下代码中存在错误:
[HttpPost]
public ActionResult Login(User model, string returnUrl)
{
if (ModelState.IsValid)
{
if (model.Login())
{
FormsAuthentication.SetAuthCookie(model.Username, true);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Invalid email address or password.");
}
}
// If execution got this far, something failed, redisplay form
return View(model);
}
此帖子从表单(登录表单)中捕获我的用户模型的实例,因此仅包含EmailAddress和密码值。它还使用此模型中的Username值(为null)来设置Authentication Cookie。
我将.Login()
方法更改为一个函数,如果找到了电子邮件地址,则该函数返回User,并且存储的哈希值与为登录时输入的密码的哈希值匹配。
因此,代码更改为以下内容(这只是更改的关键点)
// Account.Login Post
if (ModelState.IsValid)
{
var user = model.Login(model.EmailAddress);
if (user == null)
{
ModelState.AddModelError("", "Invalid email address or password.");
}
FormsAuthentication.SetAuthCookie(user.Username, true);
// create session variables n such
}
// User.Login
public User Login(string EmailAddress
{
var user = dbContext.Users.FirstOrDefault(u => u.EmailAddress == Email);
if (user == null)
throw new Exception("User not found.");
if (Hashing.ValidatePassword(Password, user.Password))
return user;
return null; // if we got here, something went wrong
}
一旦我解决了这个问题,我后来又遇到了另一个问题。与Anti-Forgery系统有关的一些问题。
虽然不是解决方案,但我设法了解了一个解决方法并从我的_LoginPartial View中注释掉了以下一行:
@Html.AntiForgeryToken()
我担心安全性,但我认为在一个基本的asp.net网站上使用密码和盐渍密码的Forms Auth已经足够好多年了,所以我在这里不应该有任何问题
答案 1 :(得分:0)
你可能会错过一些东西。在您的控制器Account
中,您有一个操作:
public ActionResult Manage(string name) // I presume name
{
....
}
然后你的行应该是:
Hello, @Html.ActionLink(User.Identity.Name, "Manage", "Account", new { name=User.Identity.Name })!
是routeValues的匿名对象 它是包含路径参数的对象。通过检查对象的属性,通过反射检索参数。该对象通常使用对象初始化器语法创建。(定义取自MSDN)它应格式良好。
我希望它能解决问题,否则你必须检查User.Identity是否与null
不同。
我也注意到了这一行中的其他内容:
var user = db.Users.FirstOrDefault(u => u.EmailAddress == EmailAddress);
EmailAddress
之后的==
来自哪里?
您应该为Login
方法提供一个参数来替换您的第二个EmailAddress
。
public bool Login(string emailAddress)
{
var user = db.Users.FirstOrDefault(u => u.EmailAddress == emailAddress);
if (user == null)
{
throw new ValidationException("User not found.");
}
else
{
// validates whether or not the password on the user record
// that was retrieved by the query matches the password entered at login
return Hashing.ValidatePassword(Password, user.Password);
}