ASP.NET Core MVC中如何发起并存储多个OAuth2外部身份验证质询
这个需求可以实现,不需要创建多份认证Cookie,基于你现有的配置做少量调整即可:
1 调整认证服务配置
首先给两套OAuth方案分别设置独立的回调路径,避免回调逻辑冲突,同时保持SaveTokens = true的配置:
.AddScheme1 (options => { options.ClientId = Configuration["Scheme1:ClientId"]; options.ClientSecret = Configuration["Scheme1:ClientSecret"]; options.Scope.Add("scope1"); options.CallbackPath = "/signin-scheme1"; // 新增独立回调路径 options.SaveTokens = true; }) .AddScheme2(options => { options.ClientId = Configuration["Scheme2:ClientId"]; options.ClientSecret = Configuration["Scheme2:ClientSecret"]; options.Scope.Add("scope1"); options.CallbackPath = "/signin-scheme2"; // 新增独立回调路径 options.SaveTokens = true; });
2 调整登录流程为分步触发质询
OAuth协议本身不支持同时触发多个身份质询,按你预期的先后登录逻辑调整Controller代码即可:
// 第一步:触发第一个方案的登录 [HttpPost("~/signin")] public IActionResult SignInFirst() { var props = new AuthenticationProperties { RedirectUri = Url.Action("SignInSecond") }; return Challenge(props, "Scheme1"); } // 第一个方案登录成功后,触发第二个方案的登录 public async Task<IActionResult> SignInSecond() { // 暂存第一个方案的令牌和声明 var scheme1Result = await HttpContext.AuthenticateAsync("Scheme1"); if (!scheme1Result.Succeeded) return RedirectToAction("SignInFirst"); var props = new AuthenticationProperties { RedirectUri = Url.Action("CompleteSignIn"), // 把第一个方案的令牌暂存到Properties里带到下一步 Items = { ["scheme1_token"] = scheme1Result.Properties.GetTokenValue("access_token"), ["scheme1_userid"] = scheme1Result.Principal.FindFirstValue(ClaimTypes.NameIdentifier) } }; return Challenge(props, "Scheme2"); } // 两个方案都登录完成后,合并信息写入Cookie public async Task<IActionResult> CompleteSignIn() { var scheme2Result = await HttpContext.AuthenticateAsync("Scheme2"); if (!scheme2Result.Succeeded) return RedirectToAction("SignInFirst"); // 取出第一步暂存的Scheme1信息 var scheme1Token = scheme2Result.Properties.Items["scheme1_token"]; var scheme1UserId = scheme2Result.Properties.Items["scheme1_userid"]; var scheme2Token = scheme2Result.Properties.GetTokenValue("access_token"); var scheme2UserId = scheme2Result.Principal.FindFirstValue(ClaimTypes.NameIdentifier); // 合并声明,创建身份 var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim("scheme1_userid", scheme1UserId)); identity.AddClaim(new Claim("scheme2_userid", scheme2UserId)); // 把两个令牌都存入认证属性 var authProps = new AuthenticationProperties(); authProps.StoreTokens(new List<AuthenticationToken> { new AuthenticationToken { Name = "scheme1_access_token", Value = scheme1Token }, new AuthenticationToken { Name = "scheme2_access_token", Value = scheme2Token } }); // 统一写入Cookie await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), authProps); return RedirectToAction("Index", "Home"); }
3 获取指定方案的令牌和用户信息
后续业务逻辑中可以直接按名称取对应信息:
// 取对应方案的令牌 var scheme1Token = await HttpContext.GetTokenAsync("scheme1_access_token"); var scheme2Token = await HttpContext.GetTokenAsync("scheme2_access_token"); // 取对应方案的用户ID var scheme1UserId = User.FindFirstValue("scheme1_userid"); var scheme2UserId = User.FindFirstValue("scheme2_userid");
关于你提到的SignInManager,它是ASP.NET Core Identity体系的组件,如果你没有用到Identity的用户存储逻辑,不需要引入它,上述自定义实现即可满足需求。
内容的提问来源于stack exchange,提问作者PeterX
相关产品推荐
相关产品推荐

