You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的注意事项

  • IAuthenticationSchemeProviderAddSchemeAsyncRemoveSchemeAsync都是异步方法,调用时要确保异步上下文正确。
  • 回调路径CallbackPath必须唯一,否则多个Provider会冲突。
  • 如果需要持久化配置,记得把OidcProviderConfig存入数据库或配置中心,应用启动时先加载已有的配置,调用AddOrUpdateOidcProviderAsync初始化。
  • 若要更新已存在的Provider,一定要先移除旧的Scheme和Options缓存,避免出现配置不一致的问题。

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

火山引擎 最新活动