Search code examples
asp.netasp.net-coreasp.net-authorization

How create custom authorization attribute for checking a role and url path in Asp.Net Core?


I want to create a custom authorization attribute for checking the role and url path.

I've find the way for doing it in the Asp.Net Core using the Policy-Based-Authorization but I've tried implement it but I can't get the HttpContext with incomming url.

AuthorizationHandlerContext hasn't access to HttpContext probable.

How can I get current HttpContext with the url path? Is it possible to do that or with another way?

I've tried this code for creating the custom Policy:

public class RoleUrlValidationHandler : AuthorizationHandler<RoleUrlValidationRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleUrlValidationRequirement requirement)
    {           
        var path = //Here I need get current url path for example - /api/posts/4545411
        var pathPart = path.Split('/');
        var clientId = pathPart[3];

        if (context.User.IsInRole(clientId))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

I want to create following:

[Authorize(Policy="RoleUrlValidation")] //Get ClientId from Url and check User's roles
public class PostsController : Controller
{
    public ActionResult Get()
    {
    }
}

Solution

  • The policy approach is the right one. Only bit you missed is, that you can use Dependency Injection in the Handlers.

    public class RoleUrlValidationHandler : AuthorizationHandler<RoleUrlValidationRequirement>
    {
        private readonly IHttpContextAccessor contextAccessor;
    
        public RoleUrlValidationHandler(IHttpContextAccessor contextAccessor)
        {
            this.contextAccessor = contextAccessor;
        }
    
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleUrlValidationRequirement requirement)
        {
            var httpContext = contextAccessor.HttpContext;
            var path = httpContext.Request.Path;
            var pathPart = path.Split('/');
            var clientId = pathPart[3];
    
            if (context.User.IsInRole(clientId))
            {
                context.Succeed(requirement);
            }
    
            return Task.CompletedTask;
        }
    }
    

    You also may have to register the IHttpContextAccessor as its not registered by default.

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    

    Extra bits:

    Consider using var routeData = httpContext.GetRouteData() instead of using path.Split('/') for reading values from it so you can easily read the parameter values from the route.