如何在OnActionExecuting中检测控制器方法是否存在指定特性?
我来帮你解决这个问题,你之前的两种方法都踩了常见的坑,咱们一步步梳理清楚:
先说说你之前的问题出在哪
第一种方法的错误:
你用了Attribute.GetCustomAttribute(context.ActionDescriptor.GetType(), typeof(AuthorizeAttribute)),这里context.ActionDescriptor.GetType()获取的是ActionDescriptor本身的类型(比如ASP.NET Core里的ControllerActionDescriptor),而不是你要检查的控制器Action方法的类型,所以肯定拿不到目标方法上的特性,返回Null是必然的。第二种方法的错误:
MethodBase.GetCurrentMethod()获取的是当前正在执行的OnActionExecuting方法本身,不是你要检测的控制器Action方法。所以就算你拿到特性,也是这个过滤器方法的特性,完全不对;而且当这个方法没有AuthorizeAttribute时,自然会抛出索引越界异常。
正确的实现方式(分ASP.NET Core和传统MVC)
针对ASP.NET Core的情况
在ASP.NET Core中,ActionExecutingContext里的ActionDescriptor如果是控制器的Action,会是ControllerActionDescriptor类型,它直接提供了目标Action的MethodInfo和控制器的ControllerTypeInfo,我们可以用这个来获取特性:
public override void OnActionExecuting(ActionExecutingContext context) { // 先确认当前Action是控制器的Action方法 if (context.ActionDescriptor is ControllerActionDescriptor actionDescriptor) { // 检查Action方法上是否存在AllowAnonymous特性 bool hasAllowAnonymous = actionDescriptor.MethodInfo .GetCustomAttributes(typeof(AllowAnonymousAttribute), inherit: true) .Any(); // 检查Action方法上是否存在Authorize特性 bool hasActionAuthorize = actionDescriptor.MethodInfo .GetCustomAttributes(typeof(AuthorizeAttribute), inherit: true) .Any(); // (可选)检查控制器类上是否存在Authorize特性 bool hasControllerAuthorize = actionDescriptor.ControllerTypeInfo .GetCustomAttributes(typeof(AuthorizeAttribute), inherit: true) .Any(); // 根据检测结果执行你的逻辑 if (hasAllowAnonymous) { // 比如跳过授权检查 } else if (hasActionAuthorize || hasControllerAuthorize) { // 执行授权验证逻辑 } } base.OnActionExecuting(context); }
针对传统ASP.NET MVC(非Core)的情况
传统MVC里对应的是ReflectedActionDescriptor,逻辑类似:
public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.ActionDescriptor is ReflectedActionDescriptor actionDescriptor) { bool hasAllowAnonymous = actionDescriptor.MethodInfo .GetCustomAttributes(typeof(AllowAnonymousAttribute), true) .Any(); bool hasActionAuthorize = actionDescriptor.MethodInfo .GetCustomAttributes(typeof(AuthorizeAttribute), true) .Any(); bool hasControllerAuthorize = actionDescriptor.ControllerType .GetCustomAttributes(typeof(AuthorizeAttribute), true) .Any(); // 后续逻辑... } base.OnActionExecuting(filterContext); }
几个关键细节
- 用
Any()代替索引访问:这样就算没有对应特性,也不会抛出索引越界异常,直接返回false,更安全。 inherit参数的作用:设为true时,会检查继承链上的特性(比如方法继承自父类的特性);如果只需要检查当前方法/控制器本身的特性,设为false即可。- 区分方法和控制器的特性:很多时候
Authorize特性会加在控制器类上,作用于所有Action,所以如果需要完整的授权逻辑,要同时检查方法和控制器的特性。
内容的提问来源于stack exchange,提问作者Santa Cloud

