


[HttpPost][AllowAnonymous][ValidateAntiForgeryToken]public async Task<IActionResult> Login(Login login){if (ModelState.IsValid){var appUser = await _userManager.FindByEmailAsync(login.Email);if (appUser != null){await _signInManager.SignOutAsync();var signInResult = await _signInManager.PasswordSignInAsync(appUser, login.Password,login.RememberMe, false);if (signInResult.Succeeded){return Redirect(login.ReturnUrl ?? "/");}if (appUser.TwoFactorEnabled){return RedirectToAction("LoginTwoStep", new { Email = appUser.Email, ReturnUrl = login.ReturnUrl });}}ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");}return View(login);}
我们可以看到在登录过程中我们查看用户是否启用双重验证,如果是则会跳转到LoginTwoStep,我们看一下LoginTwoStep是如何工作的,在AccountController中添加LoginTwoStep方法,代码如下:
[AllowAnonymous]public async Task<IActionResult> LoginTwoStep(string email, string returnUrl){var appUser = await _userManager.FindByEmailAsync(email);//创建Tokenvar token = await _userManager.GenerateTwoFactorTokenAsync(appUser ?? new AppUser(), "Email");//发送邮件_emailService.Send(appUser?.Email ?? "450190369@qq.com", "授权码", $"<h2>{token}</h2>");//发送SMS//_smsService.Send(appUser?.PhoneNumber ?? "13333333333", token);return View("LoginTwoStep", new TwoFactor { ReturnUrl = returnUrl });}[HttpPost][AllowAnonymous]public async Task<IActionResult> LoginTwoStep(TwoFactor twoFactor, string returnUrl){if (!ModelState.IsValid){return View("LoginTwoStep", new TwoFactor { TwoFactorCode = twoFactor.TwoFactorCode, ReturnUrl = returnUrl });}var result = await _signInManager.TwoFactorSignInAsync("Email", twoFactor.TwoFactorCode, false, false);if (result.Succeeded){return Redirect(returnUrl ?? "/");}else{ModelState.AddModelError("", "登录失败");return View();}}
注意:使用UserManager<T>类GenerateTwoFactorTokenAs
public class EmailSetting{public string EmailFrom { get; set; } = null!;public string EmailTo { get; set; } = null!;public string SmtpHost { get; set; } = null!;public int SmtpPort { get; set; }public string SmtpUser { get; set; } = null!;public string SmtpPass { get; set; } = null!;}public interface IEmailService{void Send(string to, string subject, string html, string from = null);}public class EmailService : IEmailService{private readonly EmailSetting _appSettings;public EmailService(IOptions<EmailSetting> options){_appSettings = options.Value;}public void Send(string to, string subject, string html, string from = null){//Create Messagevar email = new MimeMessage();email.From.Add(MailboxAddress.Parse(_appSettings.EmailFrom));email.To.Add(MailboxAddress.Parse(to));email.Subject = subject;email.Body = new TextPart(TextFormat.Html) { Text = html };//Send Mailusing var smtp = new SmtpClient();smtp.Connect(_appSettings.SmtpHost, _appSettings.SmtpPort, MailKit.Security.SecureSocketOptions.StartTls);smtp.Authenticate(_appSettings.SmtpUser, _appSettings.SmtpPass);smtp.Send(email);smtp.Disconnect(true);}}
最后,TwoFactorSignInAsync 会验证用户的token,TwoFactor类如下:
public class TwoFactor{[Required][DisplayName("授权码")]public string TwoFactorCode { get; set; } = null!;public string? ReturnUrl { get; set; }}
我们在Views->Account新建一个LoginTwoStep.cshtml视图
@model TwoFactor@{ViewData["Title"] = "输入授权码";}<div class="container"><form asp-action="LoginTwoStep" method="post"><div class="mb-3 row align-items-center"><div class="col-sm-1"><label asp-for="TwoFactorCode" class="control-label"></label><input type="hidden" name="returnUrl" value="@Model.ReturnUrl" /></div><div class="col-sm-11"><input asp-for="TwoFactorCode" class="form-control" value="@Model.TwoFactorCode" /></div></div><div class="mb-3 row align-items-center"><div class="col-sm-11 offset-sm-1"><button class="btn btn-primary" type="submit">登录</button></div></div></form></div>
3、测试整个功能
在登录页面我们输入有效的登录凭证,我们看到一个新的页面要求我们输入认证编码。如下图所示



总结
这节我们主要介绍了用户使用邮件进行双因子验证,同样方式我们可以不用修改任何逻辑进行SMS验证
源代码地址:
https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/AspNetCore.Identity/Identity