ASP.NET Core 2第三方登录往返传递邀请密钥技术问询
实现Google登录时传递邀请密钥到用户创建流程
没问题,我来一步步帮你搞定这个需求——让Google登录时能把邀请密钥mykey传递到用户创建流程里,完全适配ASP.NET Core的默认身份架构。核心思路是利用ASP.NET Core身份验证的AuthenticationProperties存储邀请密钥,因为外部登录跳转(比如到Google授权页)时,这个对象会帮我们保留状态,避免参数丢失。下面是具体的代码修改步骤:
1. 修改ExternalLogin方法
这是用户点击Google登录链接时的入口,我们需要在这里把邀请密钥存到身份验证属性里,然后发起登录挑战:
public IActionResult ExternalLogin(string provider, string key, string returnUrl = null) { // 先做个密钥有效性校验(非常推荐!防止恶意请求) if (!IsValidInvitationKey(key)) // 你需要自己实现这个校验方法,比如查数据库看密钥是否存在且未被使用 { ModelState.AddModelError("", "无效的邀请密钥,请检查链接后重试"); return RedirectToAction("Login"); } // 配置身份验证属性,把邀请密钥存到Items字典里 var authProperties = new AuthenticationProperties { // 指定授权完成后的回调地址 RedirectUri = Url.Action("ExternalLoginCallback", new { returnUrl }), Items = { { "invitation_key", key }, // 把mykey存进去,后面回调时能取到 { "returnUrl", returnUrl } } }; // 发起外部登录挑战,带上我们配置好的属性 return Challenge(authProperties, provider); }
2. 在ExternalLoginCallback中传递密钥到确认页面
Google授权完成后会回调这个方法,我们需要从AuthenticationProperties里取出之前存的密钥,再传递给用户创建的确认页面:
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null) { // 处理错误情况 if (remoteError != null) { ModelState.AddModelError("", $"授权出错: {remoteError}"); return RedirectToAction("Login"); } // 获取外部登录信息 var loginInfo = await _signInManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { ModelState.AddModelError("", "无法加载外部登录信息"); return RedirectToAction("Login"); } // 从身份验证属性中取出邀请密钥 var authResult = await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme); var invitationKey = authResult.Properties.Items["invitation_key"]; // 检查用户是否已存在,存在则直接登录 var signInResult = await _signInManager.ExternalLoginSignInAsync( loginInfo.LoginProvider, loginInfo.ProviderKey, isPersistent: false, bypassTwoFactor: true); if (signInResult.Succeeded) { // 用户已存在,这里可以根据密钥做后续处理(比如关联邀请记录) await MarkInvitationAsUsed(invitationKey); // 可选,标记密钥已使用 return LocalRedirect(returnUrl ?? "/"); } else if (signInResult.IsLockedOut) { return RedirectToAction("Lockout"); } else { // 用户不存在,准备跳转到创建页面,把密钥传递过去 var model = new ExternalLoginViewModel { Email = loginInfo.Principal.FindFirstValue(ClaimTypes.Email), InvitationKey = invitationKey // 把密钥放到ViewModel里 }; ViewData["ReturnUrl"] = returnUrl; return View("ExternalLoginConfirmation", model); } }
3. 在ExternalLoginConfirmation中使用密钥创建用户
这一步是创建新用户的核心方法,我们可以直接从ViewModel中拿到密钥,用来关联邀请信息:
先给ViewModel添加密钥属性
首先要确保你的ExternalLoginViewModel包含InvitationKey字段:
public class ExternalLoginViewModel { [Required] [EmailAddress] public string Email { get; set; } // 添加这个属性来接收邀请密钥 public string InvitationKey { get; set; } }
修改ExternalLoginConfirmation方法
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginViewModel model, string returnUrl = null) { if (!ModelState.IsValid) { return View(model); } // 获取外部登录信息 var loginInfo = await _signInManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { throw new ApplicationException("创建用户时加载外部登录信息失败"); } // 拿到传递过来的邀请密钥 var invitationKey = model.InvitationKey; // 创建新用户,这里可以把密钥关联到用户实体(比如存到User表的InvitationKey字段) var newUser = new ApplicationUser { UserName = model.Email, Email = model.Email, InvitationKey = invitationKey // 关联密钥到用户 }; // 执行用户创建 var createResult = await _userManager.CreateAsync(newUser); if (createResult.Succeeded) { // 关联外部登录信息到用户 var addLoginResult = await _userManager.AddLoginAsync(newUser, loginInfo); if (addLoginResult.Succeeded) { // 标记邀请密钥已使用(可选) await MarkInvitationAsUsed(invitationKey); // 登录新用户 await _signInManager.SignInAsync(newUser, isPersistent: false); return LocalRedirect(returnUrl ?? "/"); } AddErrors(addLoginResult); } AddErrors(createResult); ViewData["ReturnUrl"] = returnUrl; return View(model); }
最后补充:生成登录URL的格式
你需要生成类似这样的URL给用户(确保路由能正确解析provider和key参数):https://localhost:44338/account/ExternalLogin?provider=Google&key=mykey
如果你的路由是自定义的(比如/account/login/{key}),记得调整路由模板,保证ExternalLogin方法能接收到provider和key参数。
内容的提问来源于stack exchange,提问作者Murdock
相关产品推荐
相关产品推荐

