C#动态调用方法时,如何触发其关联的AppAuthorize特性?
如何在反射调用Action时触发自定义授权特性逻辑
嘿,我完全懂你的困扰——直接用反射调用StolenCar方法时,AppAuthorize特性里的授权逻辑根本不会自动执行对吧?这是因为ASP.NET MVC的过滤器(比如授权特性)是由框架的请求处理管道触发的,单纯的反射调用只会执行方法本身,不会触发附加的特性逻辑。不过咱们有两种靠谱的方法来解决这个问题:
方案一:手动获取并执行特性的授权逻辑
这种方法直接提取方法上的AppAuthorize特性,手动构造所需的上下文,然后触发它的授权逻辑,判断通过后再调用目标方法。
步骤代码示例:
Type magicType = Type.GetType(controllerFullName); MethodInfo magicMethod = magicType.GetMethod(actionName); ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes); object magicClassObject = magicConstructor.Invoke(new object[] { }); // 1. 获取方法上的所有AppAuthorize特性 var authorizeAttributes = magicMethod.GetCustomAttributes<AppAuthorize>(inherit: true); // 2. 模拟ControllerContext(根据你的场景调整,比如在Web环境下可以用当前HttpContext) Controller controller = magicClassObject as Controller; HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current); // 非Web环境需模拟 RouteData routeData = new RouteData(); routeData.Values["controller"] = magicType.Name.Replace("Controller", string.Empty); routeData.Values["action"] = actionName; ControllerContext controllerContext = new ControllerContext(httpContext, routeData, controller); // 3. 构造授权上下文并执行特性逻辑 AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext); bool isAuthorized = true; foreach (var authAttr in authorizeAttributes) { authAttr.HandleUnauthorizedRequest(authorizationContext); // 如果特性已经设置了Result(比如重定向到登录页),说明未授权 if (authorizationContext.Result != null) { isAuthorized = false; break; } } // 4. 根据授权结果决定是否调用目标方法 if (isAuthorized) { var result = magicMethod.Invoke(magicClassObject, new object[] { parameters }) as ActionResult; return result; } else { // 返回特性处理后的未授权结果 return authorizationContext.Result; }
方案二:利用MVC的ControllerActionInvoker执行Action
这种方法更贴近真实的MVC请求流程,ControllerActionInvoker会自动触发所有注册的过滤器(包括你的AppAuthorize特性),不需要手动处理特性调用。
步骤代码示例:
Type magicType = Type.GetType(controllerFullName); ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes); Controller controller = magicConstructor.Invoke(new object[] { }) as Controller; if (controller == null) { throw new InvalidOperationException("目标类型不是MVC Controller"); } // 1. 构造ControllerContext HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current); // 非Web环境需模拟 RouteData routeData = new RouteData(); routeData.Values["controller"] = magicType.Name.Replace("Controller", string.Empty); routeData.Values["action"] = actionName; controller.ControllerContext = new ControllerContext(httpContext, routeData, controller); // 2. 创建ActionInvoker并执行Action ControllerActionInvoker actionInvoker = new ControllerActionInvoker(); // 映射参数到Action的参数名(如果有多个参数需要逐个映射) var parametersDict = new Dictionary<string, object>(); var paramInfo = magicType.GetMethod(actionName).GetParameters()[0]; parametersDict[paramInfo.Name] = parameters; // 执行Action,自动触发所有过滤器逻辑 bool actionExecuted = actionInvoker.InvokeAction(controller.ControllerContext, actionName, parametersDict); // 返回执行结果 return controller.ControllerContext.Result as ActionResult;
注意事项
- 如果是在非Web环境(比如控制台程序、单元测试)调用,你需要用Moq等工具模拟
HttpContextBase、HttpRequestBase等对象,确保SecurityContext.Current和配置项能正常获取。 - 如果你有多个
AppAuthorize特性(因为你的特性设置了AllowMultiple = true),要确保所有特性的逻辑都被执行。 - 方案二的优势是能自动触发所有类型的过滤器(比如ActionFilter、ResultFilter),如果你的Controller还有其他特性,这种方法会更全面。
内容的提问来源于stack exchange,提问作者Anik Saha
相关产品推荐
相关产品推荐

