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

4.5k views Asked by At

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()
    {
    }
}
2

There are 2 answers

3
Tseng On BEST ANSWER

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.

1
Константин Черника On

Try like this:

((DefaultHttpContext)context.Resource).Request.Path.Value