Asp.Net Core 服务器运行时如何增删改authentication schemes
结论
可以在Asp.Net Core服务不重启的状态下完成认证方案(authentication schemes)的新增、修改、删除操作,但默认的内置实现不支持运行时变更,需要通过替换官方的IAuthenticationSchemeProvider实现来完成需求。
实现原理
Asp.Net Core默认的AuthenticationSchemeProvider会将服务启动时注册的所有认证方案存储在内部的只读字典中,初始化后不允许修改。我们只需要自定义该接口的实现,用线程安全的可变集合存储认证方案,再替换掉默认的服务注册即可。
核心实现步骤
1. 自定义动态认证方案提供器
using Microsoft.AspNetCore.Authentication; using System.Collections.Concurrent; public class DynamicAuthenticationSchemeProvider : IAuthenticationSchemeProvider { // 线程安全字典存储所有动态+静态认证方案 private readonly ConcurrentDictionary<string, AuthenticationScheme> _schemeCache = new(); // 可自行扩展字段存储各类默认方案配置 private AuthenticationScheme? _defaultAuthenticateScheme; public Task<AuthenticationScheme?> GetSchemeAsync(string name) { _schemeCache.TryGetValue(name, out var scheme); return Task.FromResult(scheme); } public Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync() { return Task.FromResult(_schemeCache.Values.AsEnumerable()); } public Task<AuthenticationScheme?> GetDefaultAuthenticateSchemeAsync() { return Task.FromResult(_defaultAuthenticateScheme); } // 剩余默认方案接口(Challenge、Forbid、SignIn、SignOut)可根据自身业务需求实现,也可直接复用默认逻辑 public Task<AuthenticationScheme?> GetDefaultChallengeSchemeAsync() => GetDefaultAuthenticateSchemeAsync(); public Task<AuthenticationScheme?> GetDefaultForbidSchemeAsync() => GetDefaultAuthenticateSchemeAsync(); public Task<AuthenticationScheme?> GetDefaultSignInSchemeAsync() => GetDefaultAuthenticateSchemeAsync(); public Task<AuthenticationScheme?> GetDefaultSignOutSchemeAsync() => GetDefaultAuthenticateSchemeAsync(); // 扩展新增方案方法 public Task AddSchemeAsync(AuthenticationScheme scheme) { if (scheme == null) throw new ArgumentNullException(nameof(scheme)); _schemeCache.AddOrUpdate(scheme.Name, scheme, (key, old) => scheme); return Task.CompletedTask; } // 扩展删除方案方法 public Task RemoveSchemeAsync(string schemeName) { _schemeCache.TryRemove(schemeName, out _); return Task.CompletedTask; } // 扩展设置默认方案方法 public void SetDefaultAuthenticateScheme(AuthenticationScheme scheme) { _defaultAuthenticateScheme = scheme; } }
2. 替换默认服务注册
在Program.cs中注册认证服务后,替换默认的IAuthenticationSchemeProvider实现:
var builder = WebApplication.CreateBuilder(args); // 原有认证注册逻辑保留 builder.Services.AddAuthentication(options => { // 初始默认方案配置按需填写 }) .AddJwtBearer() .AddCookie(); // 替换为自定义动态实现 builder.Services.AddSingleton<IAuthenticationSchemeProvider, DynamicAuthenticationSchemeProvider>(); // 其他服务注册、中间件配置逻辑不变
3. 运行时新增认证方案示例
可在业务代码(如控制器接口、后台服务)中直接调用自定义提供器的方法操作方案:
[ApiController] [Route("api/auth-scheme")] public class AuthSchemeController : ControllerBase { private readonly DynamicAuthenticationSchemeProvider _dynamicSchemeProvider; public AuthSchemeController(IAuthenticationSchemeProvider schemeProvider) { _dynamicSchemeProvider = (DynamicAuthenticationSchemeProvider)schemeProvider; } [HttpPost("add-jwt")] public async Task<IActionResult> AddJwtScheme(string schemeName, string authority, string audience) { // 构造新的JWT认证配置 var jwtOptions = new JwtBearerOptions { Authority = authority, Audience = audience, TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true } }; // 构造认证方案对象,指定对应的Handler类型 var newScheme = new AuthenticationScheme(schemeName, typeof(JwtBearerHandler), jwtOptions); await _dynamicSchemeProvider.AddSchemeAsync(newScheme); return Ok($"认证方案{schemeName}已添加,无需重启服务即可使用"); } }
注意事项
- 动态添加的认证方案默认不会持久化,服务重启后会丢失。如果需要持久化,可将方案配置存储在数据库、配置中心等介质,服务启动时批量加载到自定义提供器中即可。
- 涉及OAuth、OpenIdConnect等需要回调地址的第三方认证方案时,要确保动态添加的方案对应的回调路径没有冲突。
- 多线程操作时无需额外加锁,
ConcurrentDictionary已经保证了线程安全。
内容的提问来源于stack exchange,提问作者Roi Shabtai
相关产品推荐
相关产品推荐

