- 旧有逻辑是使用外部提供商(例如 Microsoft 或 GitHub)登录时,我们会从这些外部登录提供商处收到用户电子邮件。然后,我们使用此电子邮件创建本地用户帐户
- 现在我们要调整为,我们会从这些外部登录提供商处收到用户电子邮件后,创建本地用户帐户,如果未确认电子邮件地址,发送电子邮件确认链接,同时拒绝用户登录并显示错误 -“您的电子邮箱还未进行验证”
- 如果确认了电子邮件地址,则在 AspNetUserLogins 表中,添加一行用户数据,然后将当前用户登录到系统中
整个的代码和上一节基本相同,下面附上修改后的 ExternalLoginCallback:
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null){returnUrl = returnUrl ?? Url.Content("~/");var loginViewModel = new LoginViewModel{ReturnUrl = returnUrl,ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList()};if (remoteError != null){ModelState.AddModelError(string.Empty, $"外部提供程序错误: {remoteError}");return View("Login", loginViewModel);}// 从外部登录提供者,即微软账户体系中,获取关于用户的登录信息。var info = await _signInManager.GetExternalLoginInfoAsync();if (info == null){ModelState.AddModelError(string.Empty, "加载外部登录信息出错。");return View("Login", loginViewModel);}ApplicationUser user = null;// 获取邮箱地址var email = info.Principal.FindFirstValue(ClaimTypes.Email);if (email != null){// 通过邮箱地址去查询用户是否已存在user = await _userManager.FindByEmailAsync(email);// 如果电子邮件没有被确认,返回登录视图与验证错误if (user != null && !user.EmailConfirmed){ModelState.AddModelError(string.Empty, "您的电子邮箱尚未进行验证。");return View("Login", loginViewModel);}}// 如果用户之前已经登录过了,会在 AspNetUserLogins 表有对应的记录,这个时候无需创建新的记录,直接使用当前记录登录系统即可。var signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey,isPersistent: false, bypassTwoFactor: true);if (signInResult.Succeeded){return LocalRedirect(returnUrl);}// 如果 AspNetUserLogins 表中没有记录,则代表用户没有一个本地帐户,这个时候我们就需要创建一个记录了。if (email != null){if (user == null){user = new ApplicationUser{UserName = info.Principal.FindFirstValue(ClaimTypes.Email),Email = info.Principal.FindFirstValue(ClaimTypes.Email)};//如果不存在,则创建一个用户,但是这个用户没有密码。await _userManager.CreateAsync(user);var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);var confirmationLink = Url.Action("ConfirmEmail", "Account", new {userId = user.Id, token = token},Request.Scheme);_logger.Log(LogLevel.Warning, confirmationLink);ViewBag.ErrorTitle = "注册成功";ViewBag.ErrorMessage = "在你登入系统前,我们已经给您发了一份邮件,需要您先进行邮件验证,点击确认链接即可完成。";return View("Error");}// 在 AspNetUserLogins 表中,添加一行用户数据,然后将当前用户登录到系统中await _userManager.AddLoginAsync(user, info);await _signInManager.SignInAsync(user, isPersistent: false);return LocalRedirect(returnUrl);}// 如果我们获取不到电子邮件地址,我们需要将请求重定向到错误视图中。ViewBag.ErrorTitle = $"我们无法从提供商:{info.LoginProvider}中解析到您的邮件地址 ";ViewBag.ErrorMessage = "请通过联系 ltm@ddxc.org 寻求技术支持。";return View("Error");}
