负载均衡与.NET Core认证引发的302重定向循环问题排查
我之前处理过好几个类似的AWS多实例+ASP.NET Core的重定向问题,核心原因几乎都是跨实例的会话状态无法共享。你已经做了x-forward-proto转发和设置应用名称,这两步是基础,但还没触碰到问题的核心——默认情况下ASP.NET Core的数据保护密钥是本地存储的,每个实例密钥独立,导致用户在实例A生成的登录Cookie,到实例B那里根本解密不了,B会判定用户未登录并重定向到登录页,循环往复就形成了无限302。
结合你的环境(AWS负载均衡+Redis缓存+Auth0),下面是具体的解决方案:
1. 把数据保护密钥持久化到Redis(核心步骤)
既然你已经在用Redis做缓存,直接把数据保护的密钥和配置存在Redis里,让所有实例共享同一套密钥,这样不管用户请求打到哪个实例,都能正确解密登录Cookie。
操作步骤:
- 先安装对应NuGet包:
Microsoft.AspNetCore.DataProtection.Redis(适配.NET Core 2.x) - 在
Startup.cs的ConfigureServices方法中添加数据保护配置:
using StackExchange.Redis; using Microsoft.AspNetCore.DataProtection; public void ConfigureServices(IServiceCollection services) { // 1. 连接到你的Redis实例 var redisConnection = ConnectionMultiplexer.Connect("your-redis-connection-string"); // 2. 配置数据保护,共享密钥到Redis services.AddDataProtection() .SetApplicationName("Your_Exact_App_Name") // 确保所有实例的应用名称完全一致(大小写敏感) .PersistKeysToRedis(redisConnection, "DataProtection-Keys") // 指定Redis中存储密钥的Key前缀 .ProtectKeysWithDpapiNG(); // Windows实例用这个;Linux/EC2实例可改用证书加密或AWS KMS }
注意:如果是Linux实例,
DpapiNG无法使用,建议用ProtectKeysWithCertificate(把证书上传到AWS Secrets Manager让所有实例访问),生产环境不建议不加密密钥。
2. 完善负载均衡的转发头配置
你已经设置了x-forward-proto,但还要确保:
- AWS负载均衡(ALB/NLB)已开启转发
X-Forwarded-For、X-Forwarded-Proto、X-Forwarded-Host三个请求头 - 在.NET Core的
Configure方法中,必须在UseAuthentication之前添加转发头中间件:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 先配置转发头,确保认证中间件拿到正确的请求协议和主机信息 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); // 后续中间件顺序不能乱 app.UseAuthentication(); app.UseMvc(); }
这一步是为了让ASP.NET Core识别到请求是通过HTTPS进来的,避免生成的Cookie因Secure属性不匹配被浏览器拒绝。
3. 检查Auth0和Cookie的细节配置
- Auth0回调URL:确保你在Auth0控制台配置的回调URL是负载均衡的公网域名(比如
https://your-app-domain.com/signin-auth0),绝对不能用单个实例的私有IP或域名 - Cookie安全属性:在Auth0的OpenIdConnect配置中,强制Cookie仅通过HTTPS传输:
services.AddAuthentication() .AddCookie(options => { options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SameSite = SameSiteMode.Lax; // 根据跨域需求调整,Lax是默认安全选项 }) .AddOpenIdConnect("Auth0", options => { // 其他Auth0基础配置... options.CallbackPath = "/signin-auth0"; options.SaveTokens = true; });
4. 验证Redis连接和密钥存储
登录到你的Redis实例,用KEYS DataProtection-Keys*命令查看是否存在数据保护的密钥。如果没有,说明实例连接Redis有问题,检查AWS安全组是否开放了Redis端口(默认6379),以及连接字符串是否正确。
完成以上步骤后,所有实例会共享同一套数据保护密钥,用户的登录Cookie在任何实例上都能被正确解密,就能彻底解决无限302重定向的问题。
内容的提问来源于stack exchange,提问作者JHiles

