Prevent login when EmailConfirmed is false

北城余情 提交于 2019-12-17 22:13:47

问题


The newest ASP.NET identity bits (2.0 beta) include the foundation for confirming user email addresses. The NuGet package "Microsoft Asp.Net Identity Samples" contains a sample showing this flow. But in that sample, even when EmailConfirmed = false, there is no different behavior in the user experience.

How can I prevent users from being able to login when their email address is not yet confirmed? I understand that I can have the users log in regardless and then perform the check on the EmailConfirmed field, but it seems like it would be much more efficient if I could prevent the user from successfully logging in at all when EmailConfirmed == false


回答1:


You need to add a few lines to the Login action (POST method) to verify that the user has confirmed their email. The method you want to check is UserManager.IsEmailConfirmed. Here is what your Login action will look like.

    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindByNameAsync(model.Email);
            if (user == null)
            {
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
            }
            //Add this to check if the email was confirmed.
            if (!await UserManager.IsEmailConfirmedAsync(user.Id))
            {
                ModelState.AddModelError("", "You need to confirm your email.");
                return View(model);
            }
            if (await UserManager.IsLockedOutAsync(user.Id))
            {
                return View("Lockout");
            }
            if (await UserManager.CheckPasswordAsync(user, model.Password))
            {
                // Uncomment to enable lockout when password login fails
                //await UserManager.ResetAccessFailedCountAsync(user.Id);
                return await LoginCommon(user, model.RememberMe, returnUrl);
            }
            else
            {
                // Uncomment to enable lockout when password login fails
                //await UserManager.AccessFailedAsync(user.Id);
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

In this example I just return the user to the login view and display an error message. You could return them to another view that provides more details on the next steps to confirm their email, or even give them the option to resend the email confirmation.




回答2:


in ApplicationOAuthProvider.cs

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

            if (!user.EmailConfirmed)
            {
                context.SetError("invalid_grant", "Account pending approval.");
                return;
            }
        }



回答3:


I just modified the case when the login could be successfull:

case SignInStatus.Success:
    if (!await UserManager.IsEmailConfirmedAsync((await UserManager.FindByNameAsync(model.Email)).Id))
    {
        Session.Abandon();
        AuthenticationManager.SignOut();
        ModelState.AddModelError("", "You need to confirm your email address");
        return View(model);
    }
    return RedirectToLocal(returnUrl);



回答4:


Using the ASP.NET Identity 2.0 Samples.

1. Update the POST Login action in Account controller.

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doen't count login failures towards lockout only two factor authentication
        // To enable password failures to trigger lockout, change to shouldLockout: true
        var result = await SignInHelper.PasswordSignIn(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.EmailNotConfirmed:
                return View("EmailNotConfirmed");
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresTwoFactorAuthentication:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

2. Update the SignInStatus enum in IdentityConfig.cs.

public enum SignInStatus
{
    Success,
    EmailNotConfirmed,
    LockedOut,
    RequiresTwoFactorAuthentication,
    Failure
}

3. Update the PasswordSignIn method in IdentityConfig.cs.

    public async Task<SignInStatus> PasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout)
    {
        var user = await UserManager.FindByNameAsync(userName);
        if (user == null)
        {
            return SignInStatus.Failure;
        }
        if (!(await UserManager.IsEmailConfirmedAsync(user.Id)))
        {
            return SignInStatus.EmailNotConfirmed;
        }
        if (await UserManager.IsLockedOutAsync(user.Id))
        {
            return SignInStatus.LockedOut;
        }
        if (await UserManager.CheckPasswordAsync(user, password))
        {
            return await SignInOrTwoFactor(user, isPersistent);
        }
        if (shouldLockout)
        {
            // If lockout is requested, increment access failed count which might lock out the user
            await UserManager.AccessFailedAsync(user.Id);
            if (await UserManager.IsLockedOutAsync(user.Id))
            {
                return SignInStatus.LockedOut;
            }
        }
        return SignInStatus.Failure;
    }

4. Add a new View "EmailNotConfirmed.cshtml".

@{
    ViewBag.Title = "Email not confirmed";
}

<h2>You have not confirmed your email.</h2>

<p>Please click the link in the email we sent you to confirm your email.</p>

<p>todo: Add a "resend confirmation email" button here.</p>


来源:https://stackoverflow.com/questions/22153921/prevent-login-when-emailconfirmed-is-false

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!