.NET 8中如何在运行时动态修改JWT认证方案
.NET 8 运行时动态修改JWT认证方案及受众(无需重启应用)
我正在开发一个.NET 8项目,使用ASP.NET Core内置的JWT认证机制,需要在运行时动态修改(更新、删除、新增)JWT认证方案及受众信息,且无需重启应用。当前的配置与代码如下:
当前配置(appsettings.json)
{ "AuthRules": [ { "Service": "scheme1", "Audiences": [ "aud1", "aud2" ] }, { "Service": "Scheme2", "Audiences": [ "aud1", "aud2", "aud3" ] } ] }
现有JWT认证配置代码
public static void AddAuthRules(WebApplicationBuilder builder) { var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("test")); foreach (var rule in AppConfig.getValues("AuthRules")) { List<string> audiences = new List<string>(); foreach (KeyValuePair<string, string?> item in rule.GetSection("Audiences").AsEnumerable()) { if (!string.IsNullOrEmpty(item.Value)) audiences.Add(item.Value); } var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = "issExample", ValidateAudience = true, ValidAudiences = audiences, ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = false }; builder.Services.AddAuthentication() .AddJwtBearer(rule.GetSection("Service").Value!, x => { x.Events = new JwtBearerEvents { OnTokenValidated = context => { // 添加令牌验证成功的自定义逻辑 return Task.CompletedTask; }, OnAuthenticationFailed = context => { // 添加认证失败的自定义逻辑 return Task.CompletedTask; } }; x.RequireHttpsMetadata = false; x.TokenValidationParameters = tokenValidationParameters; }); } }
动态修改实现方案
现有代码在启动时一次性注册所有JWT认证方案,无法支持运行时动态变更。要实现需求,需通过配置动态加载、认证方案缓存管理来实现:
1. 启用配置实时刷新
确保appsettings.json支持自动刷新,在构建WebApplicationBuilder时添加配置:
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
2. 实现认证规则管理器
创建单例托管服务,负责监听配置变化、动态更新认证方案:
public class AuthRuleManager : IHostedService, IDisposable { private readonly IConfiguration _configuration; private readonly IAuthenticationSchemeProvider _schemeProvider; private readonly IOptionsMonitorCache<JwtBearerOptions> _jwtOptionsCache; private IDisposable? _changeToken; private readonly SymmetricSecurityKey _signingKey; public AuthRuleManager(IConfiguration configuration, IAuthenticationSchemeProvider schemeProvider, IOptionsMonitorCache<JwtBearerOptions> jwtOptionsCache) { _configuration = configuration; _schemeProvider = schemeProvider; _jwtOptionsCache = jwtOptionsCache; _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("test")); } public Task StartAsync(CancellationToken cancellationToken) { // 初始加载认证规则 LoadAuthRules(); // 监听配置变化 RegisterConfigChangeCallback(); return Task.CompletedTask; } private void RegisterConfigChangeCallback() { _changeToken?.Dispose(); _changeToken = _configuration.GetReloadToken().RegisterChangeCallback(_ => { LoadAuthRules(); RegisterConfigChangeCallback(); }, null); } private void LoadAuthRules() { var authRules = _configuration.GetSection("AuthRules").Get<List<AuthRule>>() ?? new List<AuthRule>(); // 获取当前所有JWT认证方案 var existingSchemes = _schemeProvider.GetAllSchemesAsync().Result .Where(s => s.HandlerType == typeof(JwtBearerHandler)) .Select(s => s.Name) .ToList(); // 移除已删除的认证方案 foreach (var schemeName in existingSchemes.Except(authRules.Select(r => r.Service))) { _schemeProvider.RemoveSchemeAsync(schemeName).Wait(); _jwtOptionsCache.TryRemove(schemeName); } // 更新或新增认证方案 foreach (var rule in authRules) { var tokenValidationParams = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = _signingKey, ValidateIssuer = true, ValidIssuer = "issExample", ValidateAudience = true, ValidAudiences = rule.Audiences, ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = false }; // 创建JWT选项配置 var jwtOptions = new JwtBearerOptions { Events = new JwtBearerEvents { OnTokenValidated = context => { // 令牌验证成功的自定义逻辑 return Task.CompletedTask; }, OnAuthenticationFailed = context => { // 认证失败的自定义逻辑 return Task.CompletedTask; } }, RequireHttpsMetadata = false, TokenValidationParameters = tokenValidationParams }; // 移除旧配置(若存在) _jwtOptionsCache.TryRemove(rule.Service); // 添加新配置到缓存 _jwtOptionsCache.TryAdd(rule.Service, jwtOptions); // 若方案不存在则添加 if (!existingSchemes.Contains(rule.Service)) { _schemeProvider.AddSchemeAsync(new AuthenticationScheme(rule.Service, rule.Service, typeof(JwtBearerHandler))).Wait(); } } } public Task StopAsync(CancellationToken cancellationToken) { _changeToken?.Dispose(); return Task.CompletedTask; } public void Dispose() { _changeToken?.Dispose(); } } // 用于绑定配置的模型类 public class AuthRule { public string Service { get; set; } = string.Empty; public List<string> Audiences { get; set; } = new List<string>(); }
3. 调整Program.cs中的服务注册
移除原有的AddAuthRules调用,改为注册认证基础服务和规则管理器:
var builder = WebApplication.CreateBuilder(args); // 启用appsettings实时刷新 builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); // 注册认证核心服务 builder.Services.AddAuthentication(); // 注册认证规则管理器(托管服务) builder.Services.AddSingleton<AuthRuleManager>(); builder.Services.AddHostedService(sp => sp.GetRequiredService<AuthRuleManager>()); // 其他服务注册... var app = builder.Build(); // 启用认证中间件 app.UseAuthentication(); app.UseAuthorization(); // 其他中间件配置... app.Run();
关键说明
- 配置刷新:通过
reloadOnChange: true监听appsettings文件变化,配置更新后自动触发认证规则重新加载 - 方案管理:通过
IAuthenticationSchemeProvider添加/移除认证方案,通过IOptionsMonitorCache<JwtBearerOptions>更新JWT配置 - 即时生效:所有新的认证请求会立即使用更新后的配置,无需重启应用
- 生产环境建议:示例中的固定签名密钥需替换为安全的密钥管理方案(如Azure Key Vault),配置源可替换为数据库或配置中心以提升实时性
内容的提问来源于stack exchange,提问作者Zahidli
相关产品推荐
相关产品推荐

