ASP.NET Core:即使Authorize指定Roles,如何全局应用默认授权策略?
问题根源
ASP.NET Core 授权管道的默认逻辑是:
- 当端点的
[Authorize]特性没有携带任何参数(未指定Policy、Roles、认证方案)时,管道会自动应用全局配置的DefaultPolicy完成校验 - 只要
[Authorize]特性显式指定了Roles、自定义Policy名称等参数,框架就会直接基于当前特性的参数构建独立的授权策略,完全跳过全局默认策略的合并流程,最终表现为指定了Roles后默认策略被忽略。
实现全局与逻辑合并的方案
要实现所有带[Authorize]特性的端点,都同时满足「全局默认策略要求」+「特性本身指定的校验要求」的与逻辑校验,只需要自定义授权策略提供者,替换框架默认的实现,在策略生成阶段完成规则合并即可。
步骤1:编写自定义策略提供者
继承框架内置的DefaultAuthorizationPolicyProvider,重写策略获取逻辑,在拿到任意授权策略后,自动和全局默认策略做规则合并:
public class MergedAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider { private readonly AuthorizationOptions _authorizationOptions; public MergedAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : base(options) { _authorizationOptions = options.Value; } public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { // 获取框架默认生成的策略(包含默认策略、特性指定的Roles/自定义Policy生成的策略) var originalPolicy = await base.GetPolicyAsync(policyName); // 如果拿到的就是全局配置的默认策略,直接返回即可,不需要重复合并 if (originalPolicy == _authorizationOptions.DefaultPolicy) return originalPolicy; // 合并两套策略的认证方案与授权要求,实现与逻辑 var mergedPolicyBuilder = new AuthorizationPolicyBuilder( originalPolicy.AuthenticationSchemes.Union(_authorizationOptions.DefaultPolicy.AuthenticationSchemes) ); // 把两套策略的所有授权要求都加入到构建器中,所有要求都满足才会通过校验 mergedPolicyBuilder.AddRequirements( originalPolicy.Requirements.Union(_authorizationOptions.DefaultPolicy.Requirements) ); return mergedPolicyBuilder.Build(); } }
步骤2:替换框架默认的策略提供者
在服务注册阶段,保留原有全局默认策略的配置,同时把自定义的策略提供者注册到依赖注入容器中,替换框架内置的默认实现:
// 保留你原有的全局默认策略配置 services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder(/* 填入你原有的默认策略配置逻辑 */) .Build(); }); // 注册自定义的合并策略提供者,注意生命周期和框架默认实现保持一致(单例) services.AddSingleton<IAuthorizationPolicyProvider, MergedAuthorizationPolicyProvider>();
实际效果
配置完成后:
- 不带参数的
[Authorize]依然正常应用全局默认策略 - 带
Roles参数、自定义Policy参数的[Authorize]特性,会在原有校验逻辑的基础上,叠加全局默认策略的所有校验要求,两套规则全部通过才能访问端点 - 标注了
[AllowAnonymous]的端点依然会在授权管道短路,不受合并逻辑影响,和原有框架行为完全一致 - 相同的授权要求即使被重复添加,框架内部的授权处理器也会自动去重,不会造成重复校验的性能损耗
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

