用户登录成功后未通过身份验证
User isn't authenticated after successful login
我使用来自 Visual Studio 的默认自动生成 login/password 模板创建了一个 ASP.NET MVC 应用程序。
如果我没有登录,我有一些 [Authorize] 操作可以正确地将我重定向到登录表单。当我尝试使用错误的密码登录时,我收到了预期的错误。然后,当我尝试输入正确的用户名和密码时,我没有收到任何错误,但我仍然无法访问 [Authorize] 操作。由于 Return_url 是我的 [Authorize] 操作,因此该应用程序不断地在登录表单中重定向我。我添加了 User.Identity.Name 的显示,它总是空白。
我做的第一件事就是像这样更改 Login.cshtml :
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<div style="text-align:center; margin-top:10px">
<h3>Log In</h3>
</div>
<hr />
<div style="margin-left:10px">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
</div>
<div style="margin-left:50px">
<div class="form-group">
@Html.LabelFor(m => m.User, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.User, new { placeholder = "Username", @class = "form-control" })
@Html.ValidationMessageFor(m => m.User, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.Password, new { placeholder = "Password", @class = "form-control" })
@Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
</div>
<div style="margin-left:25px">
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Connect" class="btn btn-primary btn-lg btn-block" />
</div>
</div>
</div>
}
而且我还像这样修改了 LoginViewModel :
public class LoginViewModel
{
[Required]
[Display(Name = "User")]
[DataType(DataType.Text)]
public string User { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
之后,我修改了在 HttpPOST 请求上调用的 ActionResult 登录:
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = SignInManager.CustomPasswordSignIn(model.User, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case CustomSignInStatus.Success:
return RedirectToLocal(returnUrl);
case CustomSignInStatus.Admin:
return RedirectToLocal(returnUrl);
case CustomSignInStatus.LockedOut:
return View("Lockout");
case CustomSignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, model.RememberMe });
case CustomSignInStatus.Satellite_fail:
ModelState.AddModelError("", "Satellite failed.");
return View(model);
case CustomSignInStatus.Failure:
default:
ModelState.AddModelError("", "Incorrect login or password.");
return View(model);
}
因为我需要更多登录情况(成功、管理、锁定、需要验证、Satellite_fail、失败)我创建了一个 CustomSignInStatus:
public enum CustomSignInStatus
{
//
// Summary:
// Sign in was successful
Success = 0,
//
// Summary:
// User is locked out
LockedOut = 1,
//
// Summary:
// Sign in requires addition verification (i.e. two factor)
RequiresVerification = 2,
//
// Summary:
// Sign in failed
Failure = 3,
//
// Summary:
// Satellite sign in failed
Satellite_fail = 4,
//
// Summary:
// Admin sign in
Admin = 5
}
然后我必须实现自己的 CustomPasswordSignIn 才能像这样使用我的 CustomSignInStatus :
public CustomSignInStatus CustomPasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout)
{
string hashpwd = Tools.HashData(password);
if (userName == "admin" && hashpwd == ConfigurationManager.AppSettings["ADMIN"]) return CustomSignInStatus.Admin;
using (IDal dal = new Dal())
{
int sat = dal.GetSatellite();
if (sat == -1) return CustomSignInStatus.Satellite_fail;
if (dal.CheckLogs(userName, hashpwd, sat)) return CustomSignInStatus.Success;
}
return CustomSignInStatus.Failure;
}
此方法对输入的密码进行哈希处理,验证用户是否为管理员,然后尝试验证 Satellite 和这对夫妇 login/password。
此时,身份验证似乎有效,但未创建会话,用户未通过身份验证,因此无权访问 [Authorize] 操作。我想我必须在某处添加会话创建,但我找不到代码中缺少的内容。成功登录后如何验证我的用户?
如果您正在使用 FormsAuthentication,那么当用户像这样验证时,您需要在 FormsAuthentication 中使用 SetAuthCookie
case CustomSignInStatus.Success:
FormsAuthentication.SetAuthCookie(model.User, model.RememberMe);
return RedirectToLocal(returnUrl);
我找到了解决问题的方法:
在 AccountController 中,在 Login Action 中和在 SignInManager.CustomPasswordSignIn 调用结果的开关内部,我编辑了这样的案例:
case CustomSignInStatus.Admin:
adm = true;
goto case CustomSignInStatus.Success;
case CustomSignInStatus.Success:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, model.User)
};
if (adm) claims.Add(new Claim(ClaimTypes.Role, "Administrator"));
var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
return RedirectToLocal(returnUrl);
现在我的用户已被正确识别并有权访问 [授权] 操作。
我使用来自 Visual Studio 的默认自动生成 login/password 模板创建了一个 ASP.NET MVC 应用程序。
如果我没有登录,我有一些 [Authorize] 操作可以正确地将我重定向到登录表单。当我尝试使用错误的密码登录时,我收到了预期的错误。然后,当我尝试输入正确的用户名和密码时,我没有收到任何错误,但我仍然无法访问 [Authorize] 操作。由于 Return_url 是我的 [Authorize] 操作,因此该应用程序不断地在登录表单中重定向我。我添加了 User.Identity.Name 的显示,它总是空白。
我做的第一件事就是像这样更改 Login.cshtml :
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<div style="text-align:center; margin-top:10px">
<h3>Log In</h3>
</div>
<hr />
<div style="margin-left:10px">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
</div>
<div style="margin-left:50px">
<div class="form-group">
@Html.LabelFor(m => m.User, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.User, new { placeholder = "Username", @class = "form-control" })
@Html.ValidationMessageFor(m => m.User, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.Password, new { placeholder = "Password", @class = "form-control" })
@Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)
</div>
</div>
</div>
</div>
<div style="margin-left:25px">
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Connect" class="btn btn-primary btn-lg btn-block" />
</div>
</div>
</div>
}
而且我还像这样修改了 LoginViewModel :
public class LoginViewModel
{
[Required]
[Display(Name = "User")]
[DataType(DataType.Text)]
public string User { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
之后,我修改了在 HttpPOST 请求上调用的 ActionResult 登录:
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = SignInManager.CustomPasswordSignIn(model.User, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case CustomSignInStatus.Success:
return RedirectToLocal(returnUrl);
case CustomSignInStatus.Admin:
return RedirectToLocal(returnUrl);
case CustomSignInStatus.LockedOut:
return View("Lockout");
case CustomSignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, model.RememberMe });
case CustomSignInStatus.Satellite_fail:
ModelState.AddModelError("", "Satellite failed.");
return View(model);
case CustomSignInStatus.Failure:
default:
ModelState.AddModelError("", "Incorrect login or password.");
return View(model);
}
因为我需要更多登录情况(成功、管理、锁定、需要验证、Satellite_fail、失败)我创建了一个 CustomSignInStatus:
public enum CustomSignInStatus
{
//
// Summary:
// Sign in was successful
Success = 0,
//
// Summary:
// User is locked out
LockedOut = 1,
//
// Summary:
// Sign in requires addition verification (i.e. two factor)
RequiresVerification = 2,
//
// Summary:
// Sign in failed
Failure = 3,
//
// Summary:
// Satellite sign in failed
Satellite_fail = 4,
//
// Summary:
// Admin sign in
Admin = 5
}
然后我必须实现自己的 CustomPasswordSignIn 才能像这样使用我的 CustomSignInStatus :
public CustomSignInStatus CustomPasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout)
{
string hashpwd = Tools.HashData(password);
if (userName == "admin" && hashpwd == ConfigurationManager.AppSettings["ADMIN"]) return CustomSignInStatus.Admin;
using (IDal dal = new Dal())
{
int sat = dal.GetSatellite();
if (sat == -1) return CustomSignInStatus.Satellite_fail;
if (dal.CheckLogs(userName, hashpwd, sat)) return CustomSignInStatus.Success;
}
return CustomSignInStatus.Failure;
}
此方法对输入的密码进行哈希处理,验证用户是否为管理员,然后尝试验证 Satellite 和这对夫妇 login/password。
此时,身份验证似乎有效,但未创建会话,用户未通过身份验证,因此无权访问 [Authorize] 操作。我想我必须在某处添加会话创建,但我找不到代码中缺少的内容。成功登录后如何验证我的用户?
如果您正在使用 FormsAuthentication,那么当用户像这样验证时,您需要在 FormsAuthentication 中使用 SetAuthCookie
case CustomSignInStatus.Success:
FormsAuthentication.SetAuthCookie(model.User, model.RememberMe);
return RedirectToLocal(returnUrl);
我找到了解决问题的方法:
在 AccountController 中,在 Login Action 中和在 SignInManager.CustomPasswordSignIn 调用结果的开关内部,我编辑了这样的案例:
case CustomSignInStatus.Admin:
adm = true;
goto case CustomSignInStatus.Success;
case CustomSignInStatus.Success:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, model.User)
};
if (adm) claims.Add(new Claim(ClaimTypes.Role, "Administrator"));
var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
return RedirectToLocal(returnUrl);
现在我的用户已被正确识别并有权访问 [授权] 操作。