You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core运行时动态增减AuthorizationPolicy中的认证方案

动态管理ASP.NET Core 8认证方案与授权策略的解决方案

要实现运行时开启/关闭认证方案并同步更新授权策略,核心是自定义动态授权策略提供者,替代默认的固定策略逻辑,让授权策略能实时感知当前启用的认证方案。以下是具体实现步骤:

1. 自定义动态授权策略提供者

实现IAuthorizationPolicyProvider,结合IAuthenticationSchemeProvider获取当前有效认证方案,动态构建授权策略,并加入缓存优化性能:

public class DynamicAuthorizationPolicyProvider : IAuthorizationPolicyProvider
{
    private readonly DefaultAuthorizationPolicyProvider _defaultProvider;
    private readonly IAuthenticationSchemeProvider _schemeProvider;
    private AuthorizationPolicy? _cachedDefaultPolicy;
    private readonly object _cacheLock = new();
    private readonly IConfiguration _configuration;

    public DynamicAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options, 
                                             IAuthenticationSchemeProvider schemeProvider,
                                             IConfiguration configuration)
    {
        _defaultProvider = new DefaultAuthorizationPolicyProvider(options);
        _schemeProvider = schemeProvider;
        _configuration = configuration;
    }

    public async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
    {
        // 非默认策略交给默认提供者处理
        if (!string.Equals(policyName, AuthorizationPolicy.DefaultPolicyName, StringComparison.OrdinalIgnoreCase))
        {
            return await _defaultProvider.GetPolicyAsync(policyName);
        }

        // 优先用缓存的策略,避免重复构建
        lock (_cacheLock)
        {
            if (_cachedDefaultPolicy != null) return _cachedDefaultPolicy;
        }

        // 获取所有已注册且启用的认证方案
        var enabledSchemes = (await _schemeProvider.GetAllSchemesAsync())
            .Where(s => IsSchemeEnabled(s.Name))
            .Select(s => s.Name)
            .ToList();

        // 动态构建默认授权策略
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes(enabledSchemes.ToArray())
            .Build();

        lock (_cacheLock)
        {
            _cachedDefaultPolicy = policy;
        }

        return policy;
    }

    public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
    {
        return GetPolicyAsync(AuthorizationPolicy.DefaultPolicyName) ?? _defaultProvider.GetDefaultPolicyAsync();
    }

    public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
    {
        return _defaultProvider.GetFallbackPolicyAsync();
    }

    // 刷新缓存:当认证方案启用/禁用时调用
    public void RefreshPolicyCache()
    {
        lock (_cacheLock)
        {
            _cachedDefaultPolicy = null;
        }
    }

    // 自定义判断方案是否启用的逻辑(可从配置、数据库读取)
    private bool IsSchemeEnabled(string schemeName)
    {
        // 示例:从配置读取启用状态,可替换为数据库查询等逻辑
        return schemeName switch
        {
            JwtBearerDefaults.AuthenticationScheme => true, // JWT默认始终启用
            Contants.MyCustomAuthScheme => _configuration.GetValue<bool>("Auth:CustomSchemeEnabled"),
            _ => true // 其他方案默认启用,可按需调整
        };
    }
}

2. 注册自定义提供者与认证方案

在ConfigureServices中注册自定义授权策略提供者,同时配置所有可能用到的认证方案:

var builder = WebApplication.CreateBuilder(args);

// 注册自定义授权策略提供者
builder.Services.AddSingleton<IAuthorizationPolicyProvider, DynamicAuthorizationPolicyProvider>();

// 配置所有支持的认证方案
builder.Services.AddAuthentication()
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
    {
        // 你的JWT配置逻辑,比如Authority、Audience等
    })
    .AddScheme<MyCustomAuthOptions, MyCustomAuthHandler>(Contants.MyCustomAuthScheme, options =>
    {
        // 自定义认证方案的配置
    });

// 其他服务注册...
var app = builder.Build();

// 中间件配置...
app.UseAuthentication();
app.UseAuthorization();

3. 运行时启用/禁用认证方案

在控制器中实现动态操作逻辑,修改认证方案注册状态、更新启用配置,并刷新授权策略缓存:

[ApiController]
[Route("api/auth-schemes")]
public class AuthSchemeController : ControllerBase
{
    private readonly IAuthenticationSchemeProvider _schemeProvider;
    private readonly DynamicAuthorizationPolicyProvider _policyProvider;
    private readonly IConfiguration _configuration;

    public AuthSchemeController(IAuthenticationSchemeProvider schemeProvider,
                                DynamicAuthorizationPolicyProvider policyProvider,
                                IConfiguration configuration)
    {
        _schemeProvider = schemeProvider;
        _policyProvider = policyProvider;
        _configuration = configuration;
    }

    [HttpPost("enable/{schemeName}")]
    public async Task<IActionResult> EnableScheme(string schemeName)
    {
        // 向SchemeProvider添加方案(如果未注册)
        var existingScheme = await _schemeProvider.GetSchemeAsync(schemeName);
        if (existingScheme == null)
        {
            var scheme = schemeName switch
            {
                Contants.MyCustomAuthScheme => new AuthenticationScheme(schemeName, "自定义认证", typeof(MyCustomAuthHandler)),
                // 其他方案的注册逻辑...
                _ => throw new ArgumentException("不支持的认证方案")
            };
            await _schemeProvider.AddSchemeAsync(scheme);
        }

        // 更新启用状态配置
        _configuration[$"Auth:{schemeName}Enabled"] = "true";
        // 刷新授权策略缓存
        _policyProvider.RefreshPolicyCache();

        return Ok($"已启用认证方案:{schemeName}");
    }

    [HttpPost("disable/{schemeName}")]
    public async Task<IActionResult> DisableScheme(string schemeName)
    {
        // 从SchemeProvider移除方案
        await _schemeProvider.RemoveSchemeAsync(schemeName);
        // 更新启用状态配置
        _configuration[$"Auth:{schemeName}Enabled"] = "false";
        // 刷新授权策略缓存
        _policyProvider.RefreshPolicyCache();

        return Ok($"已禁用认证方案:{schemeName}");
    }
}

关键说明

  • 自定义授权策略提供者会在每次请求默认策略时,自动读取当前启用的认证方案,无需手动修改原有固定策略。
  • 缓存机制避免了频繁查询认证方案的性能损耗,仅在方案状态变化时清空缓存。
  • 启用/禁用逻辑需同时维护IAuthenticationSchemeProvider的注册状态和启用配置,确保两端同步。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:10:41