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

容器化ASP.NET Core MVC应用Chrome登录重定向及K8多Pod异常问题

ASP.NET Core MVC容器化部署K8s+Azure AD认证的重定向与多Pod认证问题

问题背景

将基于ASP.NET Core MVC的Web应用容器化并部署到K8s集群,使用Azure AD认证时遭遇以下问题:

  • 已在Startup.cs中配置HTTPS重定向,但Chrome/Edge会重定向至/signin-oidc页面,报Correlation failed错误
  • Firefox中应用虽能运行但不稳定,偶尔报Unable to unprotect the message.State错误
  • 添加CookiePolicy配置解决了Chrome的问题,但K8s集群使用2个Pod时,请求分发到不同Pod仍出现Unable to unprotect the message.State错误

核心代码片段

Startup.cs ConfigureServices方法

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
            .AddAzureAD(options => Configuration.Bind("AzureAd", options));


    services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, (OpenIdConnectOptions options) =>
        {
            options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
             options.Events.OnAuthorizationCodeReceived = OnAuthorizationCodeReceived;

            options.Events.OnRedirectToIdentityProvider = async context =>
            {
                string redirectUri = "https://" + context.Request.Host + "/signin-oidc";; 
                AzureAdAppSettingsHelper.RedirectUriSuffix;
                context.ProtocolMessage.RedirectUri = redirectUri;
                context.ProtocolMessage.PostLogoutRedirectUri = redirectUri;
                context.Response.Redirect(redirectUri);
            };

        });

    var redisConnectionString = Environment.GetEnvironmentVariable("redcache");

    _redis = ConnectionMultiplexer.Connect(redisConnectionString);

    services.AddHttpContextAccessor();

    services.AddControllersWithViews(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        }).AddJsonOptions(jsonOptions => jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null);

    services.AddKendo();
    services.AddRazorPages();
    services.AddScoped<ICacheService, CacheService>();
    services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
}

Startup.cs Configure方法

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Err");
        app.UseHsts();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
            endpoints.MapControllerRoute(name: "Ins",
            pattern: "Ins/{*Home}",
            defaults: new { controller = "ins", action = "Home" });
        });
}

OnAuthorizationCodeReceived方法

private async static Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext ctx)
{
    var claims = new ClaimsPrincipal();
    const string AZUREADGRAPH_RESOURCE = @"https://graph.windows.net/";

    var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);

    string userId = ctx.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;

    var cache = new adowebhub.Controllers.RedisTokenCache(ctx.Options.ClientId, userId);
    var authContext = new AuthenticationContext(ctx.Options.Authority, cache);
    var result = await authContext.AcquireTokenByAuthorizationCodeAsync(ctx.ProtocolMessage.Code, new Uri(ctx.TokenEndpointRequest.RedirectUri), credential, resource: AZUREADGRAPH_RESOURCE);
    ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
}

报错信息

Chrome环境

System.Exception: An error was encountered while handling the remote login.
System.Exception: Correlation failed.

Firefox环境(偶尔出现)

System.Exception: An error was encountered while handling the remote login.

System.Exception: Unable to unprotect the message.State.

多Pod环境(添加CookiePolicy后)

System.Exception: An error was encountered while handling the remote login.

System.Exception: Unable to unprotect the message.State.

已尝试的解决方法

添加CookiePolicy配置解决了Chrome的Correlation失败问题:

app.UseCookiePolicy(new CookiePolicyOptions
{
    Secure = CookieSecurePolicy.Always
});

解决方案建议

1. 统一多Pod的Data Protection密钥

ASP.NET Core的Data Protection系统用于加密/解密认证相关的message.State,多Pod环境下每个Pod默认使用独立的密钥,导致跨Pod无法解密。利用现有Redis连接配置共享存储:

var redis = ConnectionMultiplexer.Connect(redisConnectionString);
services.AddDataProtection()
    .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys")
    .SetApplicationName("YourAppName"); // 所有Pod必须使用相同的应用名称

2. 修正OpenIdConnect重定向逻辑

当前OnRedirectToIdentityProvider事件中直接调用context.Response.Redirect(redirectUri)会中断OIDC正常流程,移除该行代码,让中间件自行处理:

options.Events.OnRedirectToIdentityProvider = async context =>
{
    string redirectUri = "https://" + context.Request.Host + "/signin-oidc";
    // 移除无效的AzureAdAppSettingsHelper.RedirectUriSuffix引用
    context.ProtocolMessage.RedirectUri = redirectUri;
    context.ProtocolMessage.PostLogoutRedirectUri = redirectUri;
    // 移除 context.Response.Redirect(redirectUri);
    await Task.CompletedTask;
};

3. 完善Cookie配置

添加SameSite属性避免跨站Cookie问题,根据业务场景调整取值:

app.UseCookiePolicy(new CookiePolicyOptions
{
    Secure = CookieSecurePolicy.Always,
    SameSite = SameSiteMode.Lax, // 跨站场景可设为None,但必须配合Secure=true
    HttpOnly = true
});

4. 临时配置K8s会话亲和性

若暂时无法配置Data Protection共享密钥,可在K8s Service中设置会话亲和性,让同一用户请求固定分发到同一Pod:

apiVersion: v1
kind: Service
metadata:
  name: your-app-service
spec:
  selector:
    app: your-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800 # 3小时

注:此为临时方案,长期需配置共享Data Protection密钥。

5. 验证Azure AD应用重定向URI

确保Azure AD应用注册中已添加https://<your-domain>/signin-oidc作为重定向URI,且与代码配置完全一致。


内容的提问来源于stack exchange,提问作者Piyush

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:57:22