成功登录后未对用户进行身份验证

时间:2019-06-26 15:06:57

标签: c# asp.net asp.net-mvc forms-authentication

我使用Visual Studio中的默认自动生成的登录名/密码模板创建了一个ASP.NET MVC应用程序。

我有一些[授权]操作,如果我没有登录,它们可以正确地将我重定向到“登录”表单。当我尝试使用错误的密码登录时,出现了预期的错误。然后,当我尝试使用正确的用户名和密码时,我没有收到任何错误,但仍然无法访问[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);
    }

因为我需要更多的登录情况(成功,管理,锁定,RequiresVerification,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和夫妇的登录名/密码。

这时,身份验证似乎正在工作,但未创建任何会话,用户未通过身份验证,因此无权访问[Authorize]操作。我想我必须在某个地方添加会话创建,但是我找不到我的代码中缺少的内容。成功登录后如何验证我的用户?

2 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法:

在AccountController中,在登录操作中以及在从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);

现在可以正确识别我的用户,并且可以访问[授权]操作。

答案 1 :(得分:0)

如果您使用的是FormsAuthentication,则需要在这样验证用户身份时在FormsAuthentication中使用SetAuthCookie

case CustomSignInStatus.Success:
FormsAuthentication.SetAuthCookie(model.User, model.RememberMe);
return RedirectToLocal(returnUrl);