限制访问,直到用户确认电子邮件链接

本文关键字:用户 确认 电子邮件 链接 访问 | 更新日期: 2023-09-27 18:08:49

我正在玩Identity。示例示例并发现用户在注册后仍然可以不点击电子邮件确认登录。是否有一个标志打开,以限制用户从登录,直到他/她点击他/她的电子邮件中的确认链接?或者我需要写任何额外的代码来防止这种情况?

编辑:从示例中添加登录操作代码

    [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 SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

限制访问,直到用户确认电子邮件链接

如果您想要求email确认,只需在您尝试passwordSignIn:

之前添加像这样的额外检查:
        var user = await UserManager.FindByNameAsync(model.Email);
        if (user != null)
        {
               if (!await UserManager.IsEmailConfirmedAsync(user.Id)) return View("ErrorNotConfirmed");
        }

像JT一样,我认为你应该在让他们知道他们必须确认电子邮件地址之前检查确保他们是经过认证的。否则,任何人都可以使用您的系统查看该电子邮件是否存在于您的系统中。所以我把Hao的代码放在了sign .success

 var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
    switch (result)
            {
                case SignInStatus.Success:
                    // Require the user to have a confirmed email before they can log on.
                    var user = await UserManager.FindByNameAsync(model.Email);
                    if (user != null)
                    {
                        if (!await UserManager.IsEmailConfirmedAsync(user.Id))
                        {                                                        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
                            ViewBag.errorMessage = "You must have a confirmed email to log on.";
                            return View("DisplayEmail");
                        }
                    }
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }

根据Hao的回复,我决定写一个我自己的"SignInManager "。方法来处理登录前的电子邮件确认。不确定这是否会帮助其他人(或者是否有更好的方法),但我想分享一下。需要注意的一点是,其功能与郝的建议略有不同。为了得到返回的"RequiresValidation",用户必须首先提供一个有效的用户名和密码。

public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
    public ApplicationSignInManager(UserManager<ApplicationUser, string> userManager, IAuthenticationManager authenticationManager) 
        : base(userManager, authenticationManager)
    {
    }
    public async Task<SignInStatus> SignInAsync(string userName, string password, bool rememberMe)
    {
        var user = await UserManager.FindByNameAsync(userName);
        if (user == null) return SignInStatus.Failure;
        if (await UserManager.IsLockedOutAsync(user.Id)) return SignInStatus.LockedOut;
        if (!await UserManager.CheckPasswordAsync(user, password))
        {
            await UserManager.AccessFailedAsync(user.Id);
            if (await UserManager.IsLockedOutAsync(user.Id))
            {
                return SignInStatus.LockedOut;
            }
            return SignInStatus.Failure;
        }
        if (!await UserManager.IsEmailConfirmedAsync(user.Id))
        {
            return SignInStatus.RequiresVerification;
        }
        await base.SignInAsync(user, rememberMe, false);
        return SignInStatus.Success;
    }
}

Update 1:经过一番思考,我认为这不适合2FA。基于其他网站的2FA实现(例如Mandrill),他们让用户输入他们的用户通行证,然后在他们被授权进入网站之前输入发送到他们手机的密码。这与在允许使用用户/pass之前仅仅验证电子邮件帐户不同。我确实更喜欢我的电子邮件确认实现,因为它不泄露用户帐户,但不是2FA

更新2:删除对GetTwoFactorEnabledAsync()的检查。上面的代码是为了防止在收到电子邮件确认之前登录,并且与2FA没有任何关系(实际上您不能使用上述方法进行2FA,因为在用户登录之前从未发送或验证令牌)。