我正在玩Identity.Samples示例,发现用户在注册后仍然无需点击电子邮件确认即可登录。是否有一个标志可以打开以限制用户登录,直到他/她单击他/她的电子邮件中的确认链接?或者我需要编写任何额外的代码来防止这种情况发生?
编辑:添加了样本中的登录操作代码
[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);
}
}
答案 0 :(得分:10)
如果您想要电子邮件确认,只需在尝试使用passwordSignIn之前添加一个类似的附加支票:
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id)) return View("ErrorNotConfirmed");
}
答案 1 :(得分:7)
与JT一样,我认为您应该检查以确保它们已通过身份验证,然后告知他们必须确认电子邮件地址。否则,任何人都可以使用您的系统查看您的系统中是否存在该电子邮件。所以我在signin.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);
}
答案 2 :(得分:5)
根据Hao的回复,我决定编写自己的“SignInManager.SignInAsync”方法来处理登录前的电子邮件确认。不确定这是否会对其他人有所帮助(或者如果有更好的方法),但我想我会分享。需要注意的一点是,功能与郝的建议略有不同。为了返回“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;
}
}
更新1 :经过一番思考后,我认为这不适合2FA。基于其他网站的2FA实施(Mandrill for one),他们让用户输入他们的用户\通行证,然后在他们被授权进入网站之前另外输入发送到他们手机的密码。这与仅在允许使用user \ pass之前验证电子邮件帐户不同。我更喜欢我的电子邮件确认实施,因为它不会泄露用户帐户,但不是2FA 。
更新2 :删除了对GetTwoFactorEnabledAsync()的检查。以上代码用于防止登录,直到收到电子邮件确认并且与2FA无关(由于在用户登录之前永远不会发送或验证令牌,因此您实际上无法使用上述方法执行2FA)