.NET8中OpenID Connect修改Azure配置无需重启的实现问询
实现Azure AD配置热更新(无需重启应用)
你的核心问题是:在AddOpenIdConnect初始化阶段直接绑定了配置的初始值,后续配置变更无法同步到OpenID Connect的选项中,同时手动创建服务容器的方式也存在问题。以下是修正方案:
关键问题分析
- 初始化
OpenIdConnectOptions时直接使用azureAdOptionsMonitor.CurrentValue,只会读取启动时的配置快照,后续文件变更不会自动更新这些属性。 - 多次调用
builder.Services.BuildServiceProvider()会生成独立的服务容器,可能导致服务实例不一致,属于不规范用法。 - 元数据缓存刷新逻辑需要和最新配置绑定,确保每次认证请求都使用最新的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配置,并更新当前请求的认证参数。
验证方法
- 修改
appsettings.json中的AzureAd节点配置(比如修改TenantId或ClientId)。 - 访问需要身份认证的页面,触发OpenID Connect跳转流程。
- 查看认证请求的参数(可通过浏览器开发者工具),确认已使用新的配置值。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

