Implementing a Custom Authorization Policy in Asp.net core

Muhammad Maaz Qureshi
2 min readJul 29, 2020

Asp.net core provides us default claims-based authorization policies in which we can require single or multiple claims from a user to be able to do an action but those are quite basic and we may quite often require a logic to use boolean operators ,access to the repository or route values for example in a case where we want to check if a request to access or update entry is made by the owner of that entry(should have same user id as the requested record) or an admin to implement that logic in this article we will learn how to write these custom complex authorization policies by extending Authorization policies with requirements and handlers

Step1:

In startup . cs add a policy in configure services like :

options.AddPolicy(“MustOwnRecordOrShouldBeInAdminRole”, policyBuilder =>

{

policyBuilder.RequireAuthenticatedUser();

policyBuilder.AddRequirements(new MustOwnRecordOrShouldBeInAdminRole());

});

step2:

Create a class requirement class that must implement the IAuthorizationRequirement interface which is defined in Microsoft.AspNetCore.Authorization like:

public class MustOwnRecordOrShouldBeInAdminRole : IAuthorizationRequirement

{

}

this requirement class can be used to store different contextual information like role name by passing it as context parameter but for now, let's keep it simple

step3:

Create a handler for that class that must inherit from AuthorizationHandler passing Requirement type as generic in it and override its method HandleRequirementAsync and write your custom logic for authorization in it like:

public class MustOwnRecordOrShouldBeInAdminRoleHandler : AuthorizationHandler<MustOwnRecordOrShouldBeInAdminRole>

{

//readonly Claim _claim;

private readonly IHttpContextAccessor _httpContextAccessor;

public MustOwnRecordOrShouldBeInAdminRoleHandler(IHttpContextAccessor httpContextAccessor)

{

_httpContextAccessor = httpContextAccessor;

}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MustOwnRecordOrShouldBeInAdminRole requirement)

{

var userId = _httpContextAccessor.HttpContext.GetRouteValue(“userId”).ToString();

if(!Guid.TryParse(userId,out Guid userIsAsGuid))

{

context.Fail();

return Task.CompletedTask;

}

var ownerId = context.User.Claims.FirstOrDefault(c => c.Type == “sub”)?.Value;

if(! (userId == ownerId))

{

context.Fail();

return Task.CompletedTask;

}

//all checks pass

context.Succeed(requirement);

return Task.CompletedTask;

}

we are injecting HttpContextAccessor which is in Microsoft.AspNetCore.Routing if it gives error you can download nugget package of the same name and to .GetRouteValue on HttpContext as above use namespace Microsoft.AspNetCore.Routing

Thats it for our handler lets return to our startup class now we must register our handler in starup as it depends on httpContextAccessor we will register it as well like :

services.AddHttpContextAccessor(); services.AddScoped<IAuthorizationHandler,

MustOwnRecordOrShouldBeInAdminRoleHandler>();

so that instance can be created on runtime when needed

if you are using repository in your handler it lifetimes shouldn't be smaller than repository lifetime otherwise it will throw an error

--

--

Muhammad Maaz Qureshi
0 Followers

Software engineer by profession,Continuous Leaner,Book lover