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

如何在应用启动前后刷新JwtBearer发现端点元数据?

解决JwtBearer元数据首请求延迟加载问题

你的问题根源在于:JwtBearer的IConfigurationManager<OpenIdConnectConfiguration>默认是延迟初始化的,只有当第一个请求触发认证逻辑时,才会创建这个管理器并拉取元数据,导致首请求耗时过长。

下面提供两种可行的解决方案:

方案一:手动创建配置管理器并预加载元数据

直接在配置JwtBearer时,手动实例化配置管理器并提前拉取元数据,然后将其绑定到选项中。这样启动阶段就完成元数据加载,不需要等到首请求。

// 先手动创建配置管理器并预加载元数据
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
    settings.DiscoveryUrl,
    new OpenIdConnectConfigurationRetriever(),
    new HttpDocumentRetriever());

// 同步预加载(如果用异步启动,可改为异步形式避免阻塞)
var config = configurationManager.GetConfigurationAsync(CancellationToken.None).GetAwaiter().GetResult();

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer("Bearer", options =>
    {
        Console.WriteLine("Configuring options");

        // 使用预加载好的配置管理器
        options.ConfigurationManager = configurationManager;
        options.AutomaticRefreshInterval = TimeSpan.FromHours(24);
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = settings.Issuer,
            ValidateAudience = true,
            ValidAudience = settings.Audience,
            ValidateLifetime = true,
        };
    });

如果项目采用异步启动(如builder.Build().RunAsync()),可将预加载代码改为异步:

var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
    settings.DiscoveryUrl,
    new OpenIdConnectConfigurationRetriever(),
    new HttpDocumentRetriever());

// 异步加载元数据
await configurationManager.GetConfigurationAsync(CancellationToken.None);

// 后续JwtBearer配置逻辑不变

方案二:启动后从认证方案中获取配置管理器并触发刷新

如果不想手动创建配置管理器,可以在应用启动完成后,从已注册的认证方案中获取JwtBearer选项,从中拿到内置的配置管理器并触发刷新。

var app = builder.Build();

// 应用启动后触发元数据加载
app.Lifetime.ApplicationStarted.Register(async () =>
{
    var schemeProvider = app.Services.GetRequiredService<IAuthenticationSchemeProvider>();
    var bearerScheme = await schemeProvider.GetSchemeAsync("Bearer");
    
    if (bearerScheme?.HandlerType == typeof(JwtBearerHandler))
    {
        var optionsMonitor = app.Services.GetRequiredService<IOptionsMonitor<JwtBearerOptions>>();
        var jwtOptions = optionsMonitor.Get("Bearer");
        
        // 主动拉取元数据
        await jwtOptions.ConfigurationManager.GetConfigurationAsync(CancellationToken.None);
        Console.WriteLine("元数据已提前加载完成");
    }
});

// 中间件配置
app.UseAuthentication();
app.UseAuthorization();

await app.RunAsync();

为什么你之前的尝试失败?

你直接请求IConfigurationManager<OpenIdConnectConfiguration>服务失败,是因为这个服务并没有被直接注册到DI容器中——它是JwtBearer在初始化时内部创建的,只有当认证方案首次被使用(即第一个请求到来)时才会实例化,所以启动阶段直接获取会提示未注册。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:17:39