ASP.Net Core 2中如何动态新增OpenID认证方案无需重启应用?
嘿,刚好在ASP.NET Core 2.x里折腾过动态添加OpenID Provider的需求,不用重启应用完全可行,核心就是利用认证系统的几个关键运行时接口来操作,给你详细捋捋:
核心思路:操作运行时的认证Scheme和配置
ASP.NET Core的认证系统是基于Authentication Schemes的,常规的ConfigureServices注册是一次性静态配置,但我们可以通过运行时的接口来动态添加/更新Scheme,不用重启应用。
1. 先搞懂几个关键接口
IAuthenticationSchemeProvider:这是管理所有认证Scheme的核心,负责Scheme的注册、查询和移除,是实现动态配置的关键。IOptionsMonitorCache<OpenIdConnectOptions>:用来缓存OpenID Connect的配置选项,因为IOptions是静态的,而IOptionsMonitor系列支持动态更新配置。
2. 基础配置先搭好
在ConfigureServices里,先注册OpenID Connect的基础服务,但不用预先配置具体的Provider:
public void ConfigureServices(IServiceCollection services) { // 注册认证基础服务 services.AddAuthentication(); // 注册OpenID Connect的Handler,不指定具体Scheme services.AddOpenIdConnect(); // 注册我们的动态管理服务 services.AddScoped<DynamicOidcProviderService>(); // 其他服务配置... }
3. 实现动态添加Provider的服务
创建一个专门的服务来处理动态添加逻辑,比如DynamicOidcProviderService:
public class DynamicOidcProviderService { private readonly IAuthenticationSchemeProvider _schemeProvider; private readonly IOptionsMonitorCache<OpenIdConnectOptions> _optionsCache; public DynamicOidcProviderService( IAuthenticationSchemeProvider schemeProvider, IOptionsMonitorCache<OpenIdConnectOptions> optionsCache) { _schemeProvider = schemeProvider; _optionsCache = optionsCache; } public async Task AddOrUpdateOidcProviderAsync(OidcProviderConfig config) { // 先检查Scheme是否已存在 var existingScheme = await _schemeProvider.GetSchemeAsync(config.SchemeName); if (existingScheme != null) { // 如果需要更新,先移除旧Scheme await _schemeProvider.RemoveSchemeAsync(config.SchemeName); // 清除旧的Options缓存 _optionsCache.TryRemove(config.SchemeName); } // 创建新的Authentication Scheme var newScheme = new AuthenticationScheme( config.SchemeName, config.DisplayName, // 显示给用户的名称,比如"GitHub登录" typeof(OpenIdConnectHandler)); // 注册Scheme到运行时 await _schemeProvider.AddSchemeAsync(newScheme); // 配置对应的OpenID Connect选项 var oidcOptions = new OpenIdConnectOptions { Authority = config.Authority, // 比如"https://github.com/login/oauth" ClientId = config.ClientId, ClientSecret = config.ClientSecret, CallbackPath = $"/signin-oidc-{config.SchemeName}", // 每个Provider的回调路径要唯一 ResponseType = "code", Scope = { "openid", "profile", "email" }, // 根据你的需求添加其他配置,比如TokenValidationParameters等 }; // 将Options存入缓存 _optionsCache.TryAdd(config.SchemeName, oidcOptions); } } // 定义Provider配置的模型 public class OidcProviderConfig { public string SchemeName { get; set; } // 唯一标识,比如"GitHubOidc" public string DisplayName { get; set; } public string Authority { get; set; } public string ClientId { get; set; } public string ClientSecret { get; set; } }
4. 动态添加和使用Provider
添加Provider的API
写一个API接口来接收新的Provider配置,触发动态添加:
[ApiController] [Route("api/oidc-providers")] public class OidcProvidersController : ControllerBase { private readonly DynamicOidcProviderService _dynamicService; public OidcProvidersController(DynamicOidcProviderService dynamicService) { _dynamicService = dynamicService; } [HttpPost] public async Task<IActionResult> AddProvider([FromBody] OidcProviderConfig config) { // 这里可以加验证逻辑,比如检查配置是否合法 await _dynamicService.AddOrUpdateOidcProviderAsync(config); return Ok("Provider added successfully"); } }
触发对应Provider的登录
在控制器里添加登录接口,让用户选择对应的Provider登录:
[HttpGet("login/{schemeName}")] public IActionResult LoginWithProvider(string schemeName) { // 检查Scheme是否存在(可选) var scheme = _schemeProvider.GetSchemeAsync(schemeName).Result; if (scheme == null) { return BadRequest("Invalid provider"); } // 发起认证挑战,跳转到对应Provider的登录页 var authProps = new AuthenticationProperties { RedirectUri = "/" // 登录成功后跳转的页面 }; return Challenge(authProps, schemeName); }
5. ASP.NET Core 2.x的注意事项
IAuthenticationSchemeProvider的AddSchemeAsync和RemoveSchemeAsync都是异步方法,调用时要确保异步上下文正确。- 回调路径
CallbackPath必须唯一,否则多个Provider会冲突。 - 如果需要持久化配置,记得把
OidcProviderConfig存入数据库或配置中心,应用启动时先加载已有的配置,调用AddOrUpdateOidcProviderAsync初始化。 - 若要更新已存在的Provider,一定要先移除旧的Scheme和Options缓存,避免出现配置不一致的问题。
内容的提问来源于stack exchange,提问作者Damien_The_Unbeliever




