ASP.NET Core IAuthorizationFilter获取顶层特性返回null
问题原因
获取控制器上的ModulePermissionAttribute始终返回null,核心原因是特性的扫描对象选错了:
- 你当前调用的
actionDescriptor.MethodInfo.GetCustomAttributes()仅会扫描当前Action方法、以及方法继承链上挂载的特性 - 标注在控制器类顶层的
ModulePermissionAttribute属于类级别特性,不在方法特性的扫描范围内,自然无法获取到返回null
除此之外你的现有代码还存在2个会导致运行/编译异常的问题:
ActionPermissionAttribute的属性写法存在递归死循环问题:原代码写的public Action action { get { return action; } }会在访问属性时反复调用自身,触发栈溢出,正确逻辑应该返回内部存储的_action私有字段ModulePermissionAttribute缺少接收Module枚举类型的构造函数,你在控制器上写的[ModulePermission(Module.Product)]传入的是枚举值,和现有构造函数的string、Type参数不匹配,会直接编译失败
修复方案
1. 修正特性类的代码问题
先修复两个特性类的写法问题,补上枚举类型的构造函数重载,匹配控制器上的标注写法:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class ActionPermissionAttribute : Attribute { private readonly Action _action; public Action Action => _action; public ActionPermissionAttribute(Action action = Action.Read) { _action = action; } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class ModulePermissionAttribute : Attribute { private readonly string _module; public string Module => _module; // 原string参数构造 public ModulePermissionAttribute(string module = "") { _module = string.IsNullOrEmpty(module) ? "Novalue" : module; } // 原Type参数构造 public ModulePermissionAttribute(Type module) { _module = module.Name; } // 新增Module枚举构造重载,匹配控制器上的枚举传参 public ModulePermissionAttribute(Module module) { _module = module.ToString(); } }
2. 从控制器类型信息上获取类级别特性
不要从MethodInfo对象上查找类级别的特性,改用ControllerActionDescriptor自带的ControllerTypeInfo属性,扫描控制器类上的标注:
public void OnAuthorization(AuthorizationFilterContext context) { bool isAuthorized = false; // 替换为你的实际授权判断逻辑 var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; if (actionDescriptor == null) { context.Result = new ForbidResult(); return; } // 从控制器类类型上获取ModulePermissionAttribute var moduleAttr = actionDescriptor.ControllerTypeInfo .GetCustomAttributes<ModulePermissionAttribute>(true) .FirstOrDefault(); // 从Action方法上获取ActionPermissionAttribute,原有这部分逻辑是正确的 var actionAttr = actionDescriptor.MethodInfo .GetCustomAttributes<ActionPermissionAttribute>(false) .FirstOrDefault(); // 此处编写基于moduleAttr、actionAttr的权限校验逻辑 if (moduleAttr == null || actionAttr == null) { // 未标注权限特性的接口可按需处理,比如默认禁止访问 isAuthorized = false; } if (!isAuthorized) { context.Result = new ForbidResult(); } }
扩展说明
如果需要支持个别Action覆盖控制器定义的模块权限,可以先扫描当前Action方法上是否存在ModulePermissionAttribute,能取到值就优先用Action上的配置,取不到再回退读取控制器类上的特性,实现更灵活的权限标注规则。
内容的提问来源于stack exchange,提问作者BUlle7
相关产品推荐
相关产品推荐

