Home > database >  Custom Authorization Filter has exception in run time
Custom Authorization Filter has exception in run time

Time:11-29

I'm using my custom authorization filter as it's here How do you create a custom AuthorizeAttribute in ASP.NET Core? but in run time get this error: "InvalidOperationException: A suitable constructor for type 'papillon.Common.RoleRequirementFilter' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.'. " Should I change some code in my startup.cs ?!?!

this is my AuthorizationFilter

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();
    }
}

this is my TypeFilterAttribute

public class RoleRequirementAttribute : TypeFilterAttribute
{
    public RoleRequirementAttribute(string[] roleNames) : base(typeof(RoleRequirementFilter))
    {
        Arguments = roleNames;
    }
}

this is my 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();
});

and this is how I use it in my controller

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

CodePudding user response:

TypeFilterAttribute.Arguments is the array of objects that will be passed to the constructor of the filter you are constructing. Your filter has a single constructor parameter roleNames which happens to be a string array. But by setting Arguments = roleNames you are effectively telling the framework to pass each role name as an individual argument to the filter’s constructor. But since your filter does not have a variable number of string parameters (but just a single string array parameter), this will not match up.

So instead, you should adjust your type filter to pass the string array itself as the sole argument to your filter:

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

CodePudding user response:

you can define your roles as enum, then use ResultFilterAttribute in order to accept any inRole Users like this:

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);

        }
    }

in above any controller you can use this attribute like this:

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