跨域Silent Renew异常求助:client2.com触发login_required错误
我有两个不同域名的客户端client1.com、client2.com,Identity Server部署在auth.client1.com。其中client1.com的静默续期(Silent Renew)功能正常,但client2.com执行静默续期时触发错误,页面变为空白,错误信息如下:
"Error: AuthCallback AuthResult came with error: login_required"
附上我的Startup.cs代码:
public void ConfigureServices(IServiceCollection services) { services.ConfigureNonBreakingSameSiteCookies(); services.AddControllersWithViews(); string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; string connectionString = "<connectionString>"; services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); services.AddIdentity<ApplicationUser, ApplicationRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }) .AddConfigurationStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }) .AddOperationalStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); options.EnableTokenCleanup = true; }).AddAspNetIdentity<ApplicationUser>(); string cerFileName = "<cerFileName>"; string cerPassword = "<cerPassword>"; if (Environment.IsDevelopment()) { string fileName = Path.Combine(Environment.ContentRootPath, "tempkey.rsa"); builder.AddDeveloperSigningCredential(filename: fileName); } else { if (!File.Exists(cerFileName)) { throw new FileNotFoundException("Signing Certificate is missing!"); } X509Certificate2 cert = new X509Certificate2(cerFileName, cerPassword, X509KeyStorageFlags.MachineKeySet); builder.AddSigningCredential(cert); Console.WriteLine("###Certificate is done"); } string authorityUrl = Configuration.GetValue<string>("<AuthorityUrl>"); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, jwt => { jwt.Authority = authorityUrl; jwt.TokenValidationParameters = new TokenValidationParameters() { ValidateAudience = false, }; jwt.RequireHttpsMetadata = false; }); // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddTransient<ISmsSender, AuthMessageSender>(); services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings")); } public void Configure(IApplicationBuilder app) { using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope()) { SeedData.EnsureSeedData(scope.ServiceProvider, Configuration); } app.UseCookiePolicy(); if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseIdentityServer(); ///app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); }
login_required错误在跨域静默续期场景下,通常是Identity Server无法识别客户端的登录会话,或跨域配置缺失导致,你需要检查并补充以下配置:
Identity Server的Cookie跨域适配
由于client2.com与auth.client1.com跨域,需要调整登录Cookie的属性,确保跨域请求能携带会话凭证:services.ConfigureApplicationCookie(options => { options.Cookie.SameSite = SameSiteMode.None; options.Cookie.Domain = ".client1.com"; // 开头的点适配所有子域 options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 生产环境必须配合HTTPS });同时确保
ConfigureNonBreakingSameSiteCookies()的配置不会覆盖上述SameSite设置。client2的Identity Server客户端配置
检查Identity Server中client2.com的客户端元数据,确保:AllowedCorsOrigins包含https://client2.com(完整域名);AllowedGrantTypes包含implicit或authorization_code(匹配你的静默续期流程);RedirectUris添加静默续期回调地址(比如https://client2.com/silent-renew.html);AllowAccessTokensViaBrowser设置为true,允许浏览器端获取令牌。
添加CORS中间件并调整顺序
在Configure方法中,将CORS中间件放在UseIdentityServer之前,允许跨域携带凭证:app.UseCors(options => { options.WithOrigins("https://client1.com", "https://client2.com") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 必须开启,允许携带Cookie }); app.UseIdentityServer();客户端静默续期请求配置
客户端发起静默续期时,必须开启withCredentials: true,确保请求携带Identity Server的登录Cookie。以oidc-client-js为例:const userManager = new UserManager({ authority: 'https://auth.client1.com', client_id: 'client2', redirect_uri: 'https://client2.com/callback.html', silent_redirect_uri: 'https://client2.com/silent-renew.html', response_type: 'id_token token', scope: 'openid profile', withCredentials: true // 关键配置,确保携带Cookie });HTTPS环境检查
生产环境中,SameSite=None的Cookie要求必须使用HTTPS,否则浏览器会拒绝携带凭证;开发环境需启用ASP.NET Core的开发HTTPS证书。
内容的提问来源于stack exchange,提问作者HasanGundogdu

