自定义授权过滤器在运行时出现异常

Posted

技术标签:

【中文标题】自定义授权过滤器在运行时出现异常【英文标题】:Custom Authorization Filter has exception in run time 【发布时间】:2022-01-05 12:06:15 【问题描述】:

我正在使用我的自定义授权过滤器,因为它在这里 How do you create a custom AuthorizeAttribute in ASP.NET Core? 但在运行时得到这个错误: “InvalidOperationException:找不到适合类型 'papillon.Common.RoleRequirementFilter' 的构造函数。确保类型是具体的,并且为公共构造函数的所有参数注册了服务。”。 " 我应该更改我的 startup.cs 中的一些代码吗?!?!

这是我的授权过滤器

public class RoleRequirementFilter : IAuthorizationFilter

    private readonly string[] _rolesNames;

    public RoleRequirementFilter(string[] roleNames)
    
        _rolesNames = roleNames;
    
    public void OnAuthorization(AuthorizationFilterContext context)
    
        if (context.HttpContext.User.IsInRole("Support"))
            return;

        foreach (var item in _rolesNames)
            if (context.HttpContext.User.IsInRole(item))
                return;

        context.Result = new ForbidResult();
        // context.Result = new UnauthorizedResult();
    

这是我的 TypeFilterAttribute

public class RoleRequirementAttribute : TypeFilterAttribute

    public RoleRequirementAttribute(string[] roleNames) : base(typeof(RoleRequirementFilter))
    
        Arguments = roleNames;
    

这是我的 startup.cs

services.AddControllersWithViews().AddRazorRuntimeCompilation();

// ...

app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>

    endpoints.MapControllerRoute(
        name: "default",
        pattern: "controller=Home/action=Index/id?").RequireAuthorization();

    endpoints.MapRazorPages().RequireAuthorization();
);

这就是我在控制器中使用它的方式

[RoleRequirement(roleNames:new string[]Roles.Admin1, Roles.Admin2, Roles.Center1)]

【问题讨论】:

【参考方案1】:

TypeFilterAttribute.Arguments 是将传递给您正在构建的过滤器的构造函数的对象数组。您的过滤器有一个构造函数参数roleNames,它恰好是一个字符串数组。但是通过设置Arguments = roleNames,您实际上是在告诉框架将每个角色名称作为单独的参数传递给过滤器的构造函数。但是由于您的过滤器没有可变数量的字符串参数(而只是一个字符串数组参数),所以这将不匹配。

因此,您应该调整类型过滤器以将字符串数组本身作为唯一参数传递给您的过滤器:

public class RoleRequirementAttribute : TypeFilterAttribute

    public RoleRequirementAttribute(string[] roleNames) : base(typeof(RoleRequirementFilter))
    
        Arguments = new object[]  roleNames ;
    

【讨论】:

谢谢你,现在我在将它用于控制器时遇到了另一个问题,[AllowAnonymous] 不起作用 @Soheil 如果存在[AllowAnonymous],则默认情况下不会跳过自定义授权过滤器。如果您想将该行为应用于您的授权过滤器,则必须以与[Authorize] 过滤器相同的方式显式检查它。见this answer on how to do that。【参考方案2】:

您可以将您的角色定义为枚举,然后使用 ResultFilterAttribute 来接受任何这样的 inRole 用户:

public class UserAuthorization : ResultFilterAttribute
    
        RolesEnum[] _roles;
        public UserAuthorization(RolesEnum[] roles)
        
            _roles = roles;
        
        public override void OnResultExecuting(ResultExecutingContext context)
        
           
            // if not in role throw exception
            base.OnResultExecuting(context);

        
    

在上面的任何控制器中,你都可以像这样使用这个属性:

[UserAuthorization(new RolesEnum[]  RolesEnum.Admin1, RolesEnum.Branch1,RolesEnum.Center1 )]
    public class MyController : Controller

【讨论】:

以上是关于自定义授权过滤器在运行时出现异常的主要内容,如果未能解决你的问题,请参考以下文章

使用 TestRestTemplate 时出现异常

MVC 自定义过滤器(Filter)实现路由控制异常处理授权处理(获取客户端信息)

Django:在使用模板继承时在基本模板文件中加载自定义过滤器时出现问题

在自定义适配器上使用.getFilter()时出现问题(未正确过滤)(Android)

按分区过滤 system.parts (ClickHouse) 时出现异常

MVC过滤器:自定义授权过滤器