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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:05:21