You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:10:36