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

.NET8中OpenID Connect修改Azure配置无需重启的实现问询

实现Azure AD配置热更新(无需重启应用)

你的核心问题是:在AddOpenIdConnect初始化阶段直接绑定了配置的初始值,后续配置变更无法同步到OpenID Connect的选项中,同时手动创建服务容器的方式也存在问题。以下是修正方案:

关键问题分析

  1. 初始化OpenIdConnectOptions时直接使用azureAdOptionsMonitor.CurrentValue,只会读取启动时的配置快照,后续文件变更不会自动更新这些属性。
  2. 多次调用builder.Services.BuildServiceProvider()会生成独立的服务容器,可能导致服务实例不一致,属于不规范用法。
  3. 元数据缓存刷新逻辑需要和最新配置绑定,确保每次认证请求都使用最新的Azure AD参数。

修正后的完整代码

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Options;
using OpenIDConnect.Models;
using OpenIDConnect.Services;

var builder = WebApplication.CreateBuilder(args);

// 配置源已开启自动重载,无需修改
var configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables();

var configurationRoot = configurationBuilder.Build();
builder.Configuration.AddConfiguration(configurationRoot);

// 注册配置和服务
builder.Services.Configure<AzureAdOptions>(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddSingleton<IConfigureOptions<AzureAdOptions>, ConfigureAzureAdOptions>();
builder.Services.AddSingleton<JsonConfigService>();
builder.Services.AddSingleton<CustomOpenIdConnectService>();

// 配置认证
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    // 只配置固定不变的基础选项,动态配置放到事件中处理
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.UsePkce = true;
    options.Scope.Add("offline_access");
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    // 在跳转身份提供商事件中实时获取最新配置
    options.Events.OnRedirectToIdentityProvider = async context =>
    {
        // 通过HttpContext获取当前服务容器,避免手动创建
        var azureAdOptionsMonitor = context.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<AzureAdOptions>>();
        var azureAdOptions = azureAdOptionsMonitor.CurrentValue;
        var openIdConnectService = context.HttpContext.RequestServices.GetRequiredService<CustomOpenIdConnectService>();

        // 刷新元数据缓存
        await openIdConnectService.InvalidateMetadata(azureAdOptions.TenantId, azureAdOptions.ClientId, azureAdOptions.ClientSecret, azureAdOptions.Domain);

        // 动态更新当前请求的认证选项
        context.Options.ClientId = azureAdOptions.ClientId;
        context.Options.Authority = $"https://login.microsoftonline.com/{azureAdOptions.TenantId}/v2.0";
        context.Options.ClientSecret = azureAdOptions.ClientSecret;
        context.ProtocolMessage.DomainHint = azureAdOptions.Domain;
    };
});

builder.Services.AddAuthorization();
builder.Services.AddRazorPages();

var app = builder.Build();

// 补充完整中间件配置
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

核心修改点说明

  • 移除初始化阶段的动态配置绑定:只保留固定的OpenID Connect选项,动态配置全部移到OnRedirectToIdentityProvider事件中处理。
  • 通过HttpContext获取服务:使用context.HttpContext.RequestServices获取IOptionsMonitor和自定义服务,避免手动创建服务容器。
  • 确保每次认证请求都读取最新配置:每次触发登录跳转时,都会实时拉取appsettings.json中的最新Azure AD配置,并更新当前请求的认证参数。

验证方法

  1. 修改appsettings.json中的AzureAd节点配置(比如修改TenantId或ClientId)。
  2. 访问需要身份认证的页面,触发OpenID Connect跳转流程。
  3. 查看认证请求的参数(可通过浏览器开发者工具),确认已使用新的配置值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:00:02