IdentityServer4 API宕机时,带[Authorize]的Blazor应用崩溃
解决方案
1. 核心问题分析
你的应用崩溃是因为OIDC配置文档(/.well-known/openid-configuration)加载失败,这个过程发生在认证挑战触发之前,所以你配置的OnAuthenticationFailed、OnRemoteFailed等事件不会触发——这些事件仅在认证流程启动后才会执行。要解决问题,需要从配置加载环节和全局异常处理两方面入手。
2. 配置OIDC异常拦截
自定义Backchannel与配置加载检查
修改你的OIDC配置,添加异常捕获逻辑,同时在Cookie认证的跳转事件中提前验证配置可用性:
builder.Services.AddHttpContextAccessor(); builder.Services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }).AddOpenIdConnect("oidc", options => { // 原有配置保留 options.Authority = "https://localhost:18100"; options.ClientId = "client_id"; options.ResponseType = "code"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash", "s_hash", "at_hash", "displayname", "givennames", "familyname", "roles"); options.ClaimActions.MapJsonKey("role", "roles"); options.ClaimActions.MapUniqueJsonKey("family_name", "familyname"); options.ClaimActions.MapUniqueJsonKey("given_name", "givennames"); options.ClaimActions.MapUniqueJsonKey("name", "displayname"); options.SignOutScheme = "oidc"; options.UseTokenLifetime = false; options.Scope.Add("openid"); options.Scope.Add("profile"); options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role" }; options.SignedOutCallbackPath = "/signout-callback-oidc"; options.SignedOutRedirectUri = "/ui"; // 添加自定义Backchannel,设置超时 options.BackchannelTimeout = TimeSpan.FromSeconds(5); options.BackchannelHttpHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; // 配置认证事件,处理流程内异常 options.Events = new OpenIdConnectEvents { OnRemoteFailure = context => { context.Response.Redirect("/error?message=认证服务不可用"); context.HandleResponse(); return Task.CompletedTask; }, OnAuthenticationFailed = context => { context.Response.Redirect("/error?message=认证流程失败"); context.HandleResponse(); return Task.CompletedTask; } }; }).AddCookie("Cookies", options => { // 在跳转登录前检查OIDC配置是否可访问 options.Events = new CookieAuthenticationEvents { OnRedirectToLogin = async context => { try { var configManager = context.HttpContext.RequestServices.GetRequiredService<IConfigurationManager<OpenIdConnectConfiguration>>(); await configManager.GetConfigurationAsync(context.HttpContext.RequestAborted); } catch { // 配置加载失败,直接跳错误页 context.Response.Redirect("/error?message=认证服务暂时不可用"); context.HandleResponse(); } } }; }); builder.Services.AddAuthorization();
3. 配置Blazor全局错误页
添加异常处理中间件
在Program.cs中注册全局异常处理:
if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); }
创建错误页Error.razor
@page "/error" @inject IHttpContextAccessor HttpContextAccessor <h1>服务暂时不可用</h1> <p>@HttpContextAccessor.HttpContext?.Request.Query["message"]</p> <p>请稍后重试,或联系管理员。</p>
4. 关键注意事项
HandleResponse()必须调用:在事件处理中调用该方法才能终止原有认证流程,避免异常冒泡导致应用崩溃。- 配置加载提前检查:在
OnRedirectToLogin中提前验证OIDC配置可用性,拦截配置加载失败的场景。 - Backchannel超时设置:合理设置超时时间,避免请求长时间挂起占用资源。
内容的提问来源于stack exchange,提问作者SWEATS
相关产品推荐
相关产品推荐

