如何通过TypeFilterAttribute向IAsyncAuthorizationFilter正确传参
问题根因
两次代码抛出相同异常的核心原因是TypeFilterAttribute基类的构造参数传错了:TypeFilterAttribute的构造函数需要传入实际执行过滤逻辑的过滤器实现类型,但你两次都传入了特性类自身的类型typeof(SimpleAuthorizeServiceAttribute),导致框架尝试创建特性类本身的实例作为过滤器,同时用你赋值的Arguments(仅包含一个PermissionData对象)去匹配特性类的构造函数。你的特性类构造函数需要的是(string, string, AccessType)或者params string[]参数,和Arguments里的参数完全不匹配,自然会抛出找不到合适构造函数的异常。
正确实现代码
你不需要改成弱类型的字符串传参,修正基类传入的类型即可保留强类型参数的优势,完整实现如下:
// 权限参数实体、访问枚举如果已经在项目中定义,无需重复编写 public class PermissionData { public string Service { get; set; } public string Context { get; set; } public AccessType Access { get; set; } public PermissionData(string service, string context, AccessType access) { Service = service; Context = context; Access = access; } } public enum AccessType { Read, Write, Delete } public class SimpleAuthorizeServiceAttribute : TypeFilterAttribute { // *核心修正*:base构造传入真正的过滤器实现类型,而非特性自身类型 public SimpleAuthorizeServiceAttribute(string service, string context, AccessType access) : base(typeof(SimpleAuthorizeServiceFilter)) { // 按过滤器构造函数的参数顺序,传入自定义参数 Arguments = new object[] { new PermissionData(service, context, access) }; } private class SimpleAuthorizeServiceFilter : IAsyncAuthorizationFilter { private readonly PermissionData _permissionData; // 构造函数支持两类参数: // 1. 你在Arguments中传入的自定义参数 // 2. DI容器中注册的任意服务,框架会自动注入,不需要手动传入Arguments public SimpleAuthorizeServiceFilter(PermissionData permissionData) { _permissionData = permissionData; } public Task OnAuthorizationAsync(AuthorizationFilterContext context) { // 编写实际授权判断逻辑 var allowAccess = _permissionData.Service != null; if (!allowAccess) { context.Result = new ForbidResult(); } return Task.CompletedTask; } } }
使用方式
直接在控制器Action或者控制器类上标注特性即可,支持强类型枚举传参:
[HttpGet] [SimpleAuthorizeService("test-service", "test-context", AccessType.Read)] public async Task<bool> ServiceTest() { bool isAllowed = this.HttpContext.IsUserAllowedToAccess(10, 20, 30); return isAllowed; }
注意事项
- 不需要使用
params string[]做弱类型传参,只要基类构造传入的过滤器类型正确,强类型枚举、自定义对象参数都可以正常传递 - 过滤器的构造函数除了接收
Arguments里传入的自定义参数,还可以直接注入DI容器注册的服务,框架会自动解析依赖,不需要手动传值 - 如果你的授权逻辑不需要依赖DI注入的服务,也可以直接让特性类实现
IAsyncAuthorizationFilter接口,在特性类中直接写授权逻辑,这种方式不需要继承TypeFilterAttribute,但无法自动注入DI服务,灵活性较差
内容的提问来源于stack exchange,提问作者JensB
相关产品推荐
相关产品推荐

