.NET 8 Web应用EF/Identity与Entra、Google SSO共存认证问题
解决.NET 8中Identity本地认证与Entra/Google SSO共存的问题
核心问题分析
你的问题根源在于重复调用AddAuthentication覆盖了默认配置,且Identity与第三方认证使用了不同的Cookie认证方案,导致登录状态无法在后续请求中被正确识别:
- 每次调用
AddAuthentication都会重置默认认证方案,最后一次调用的方案会成为唯一生效的默认值 - Identity默认使用
IdentityConstants.ApplicationScheme作为Cookie方案,而你为Google配置的是CookieAuthenticationDefaults.AuthenticationScheme,两者不统一
修复步骤
1. 统一认证配置(Program.cs)
修改Program.cs中的认证配置,只调用一次AddAuthentication,统一Cookie方案,并添加所有认证方式:
// 1. 配置Identity(使用自定义用户和角色) builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options => { options.SignIn.RequireConfirmedAccount = false; }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders() .AddSignInManager<SignInManager<ApplicationUser>>(); // 2. 统一配置认证,设置默认Cookie方案为Identity的ApplicationScheme builder.Services.AddAuthentication(options => { // 默认认证方案使用Identity的Cookie方案,确保本地登录和SSO登录都使用同一个Cookie options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme; options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ApplicationScheme; }) // 添加Azure Entra认证 .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph")) .AddInMemoryTokenCaches() // 回到认证配置链,添加Google认证 .AddGoogle(googleOptions => { googleOptions.ClientId = AppConfig.GetValue("Google:ClientId"); googleOptions.ClientSecret = AppConfig.GetValue("Google:ClientSecret"); googleOptions.Events = new Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents { OnRedirectToAuthorizationEndpoint = context => { context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; } }; }); // 确保添加Authorization中间件 builder.Services.AddAuthorization();
2. 调整Google登录回调的Cookie方案
修改LoginGoogleResponse方法,使用Identity的Cookie方案而非通用Cookie方案:
[HttpGet, HttpPost, ViewPath] [Route("login/google-response")] public async Task<IActionResult> LoginGoogleResponse() { // 使用Identity的默认Cookie方案 string authScheme = IdentityConstants.ApplicationScheme; var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme); if (result?.Succeeded == true) { // 创建ClaimsIdentity时指定Identity的认证方案 var claimsIdentity = new ClaimsIdentity(result.Principal.Claims, authScheme, ClaimTypes.Name, ClaimTypes.Role); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); var authProperties = new AuthenticationProperties { IsPersistent = true }; await HttpContext.SignInAsync(authScheme, claimsPrincipal, authProperties); return Redirect("/"); } else { return Challenge(GoogleDefaults.AuthenticationScheme); } }
3. 验证本地登录的Scheme一致性
你的本地登录方法已正确使用IdentityConstants.ApplicationScheme,无需修改,但确保SignInManager.SignInAsync使用默认方案即可。
4. 调整中间件顺序(关键!)
在Program.cs末尾,确保中间件顺序正确:
var app = builder.Build(); // 其他中间件(如静态文件、路由等)... // 必须先添加Authentication中间件,再添加Authorization中间件 app.UseAuthentication(); app.UseAuthorization(); // 端点路由等... app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
修复原理
- 统一Cookie方案:所有登录方式都使用
IdentityConstants.ApplicationScheme作为Cookie方案,确保后续请求能识别同一个Cookie中的登录状态 - 单次AddAuthentication配置:避免重复调用覆盖默认方案,所有认证方式都添加到同一个认证配置链中
- 正确的中间件顺序:
UseAuthentication必须在UseAuthorization之前,确保请求先经过认证验证,再进行授权检查 - 明确指定认证方案:在Challenge和SignIn时明确指定对应的方案,避免默认方案冲突
内容的提问来源于stack exchange,提问作者user5974635
相关产品推荐
相关产品推荐

