![]() |
| Claim Based Authorization in ASP.NET Core |
Role Based Authorization works well when we want to restrict access based on user roles. But modern aplications required more granular control on authorization. Claim Based Authorization allows or restricts permission based on user's identity such as Date Of Birth, Department, Gender etc rather than what the role user is assigned to. In this article, we'll discuss about claims, how to store them using asp.net core identity and how to apply authorization based on that.
If you're new to ASP.NET Core Identity or want to know about Authentication and Authorization using ASP.NET Core Identity, please check out the articles:
- Introduction to Authentication and ASP.NET Core Identity
- Authenticate Web API using ASP.NET Core Identity
- Introduction to Authorization in ASP.NET Core
- Role Based Authorization in ASP.NET Core
What is Claim Based Authorization
Before understanding Claim Based Authorization, we must know what is a claim.
What is a Claim
A claim is a key-value pair representing user attributes, issued by a trusted authority, and used by the system to make authorization decisions.
For e.g. when we register into an application we provide our personal information like name, email, dob, mobile, gender etc. After authenticating into an application these informations are packaged into the form of Authentication Cookie or Token. All information present there about user can be considered as claims.
In our case the issuing authority is ASP.NET Core Identity.
In ASP.NET Core, claims can be found under HttpContext.ClaimsPrincipal.Identities property. Also, ClaimsPrincipal.Claims provides the list of claims as a shortcut and most of the cases we can use this.
During an HttpRequest after the Cookie or Token is validated, ASP.NET Core attaches the claims to ClaimsPrincipal, packaged in the cookie or token, so that code running later in the same http request has instant access to claims.
ASP.NET Core Identity by default adds few claims after authentiation. But if we want to add custom claim, we've to configure based on our requirement.We'll understand how to add claims as well.
Claim Based Authorization
Claim Based Authorization is giving access to endpoint or resource to user based on the claims. It basically verifies if the particular user has the corresponding claim. Based on that it allows the user the endpoint.
E.g. we want an endpoint to be accessible to users of certain age. As we can have DOB in our claim so we can authorize based on the age.
Another example can be based on gender.
There can be many scenarios, we've to identify when to use Claim Based Authorization based on the requirement.
Implement Claim Based Authorization
Before diving into implementation, we've to know how to add claims for a user. Here we'll add claims for ASP.NET Core Identity.
Add User Claims
By default, ASP.NET Core Identity adds UserId, UserName and Email to the claimsPrincipal. However, if needed we can add custom claim as per our requirement. There are two ways add claims to HttpContext.ClaimsPrincipal.Claims.
- Using Custom ClaimsTransformation
- By adding claims to AspNetUseClaims table
Using IClaimsTransformation
The IClaimsTransformation can be used to add extra claims to ClaimsPrincipal using the TransformAsnc().
using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;
public class CustomClaimsTransformation : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity();
var claimType = "testClaimName";
if (!principal.HasClaim(claim => claim.Type == claimType))
{
claimsIdentity.AddClaim(new Claim(claimType, "testClaimValue"));
}
principal.AddIdentity(claimsIdentity);
return Task.FromResult(principal);
}
}
Register the class in program.cs
builder.Services.AddTransient<IClaimsTransformation, CustomClaimsTransformation>();
Adding claims to AspNetUseClaims table
In ASP.NET Core Identity there is a table named AspNetUserClaims, there we can add custom claims for a user as well. It will automatically add the claims from that table to ClaimsPrincipal after Authentication is validated.
Use AspNetUserClaims when we need to add temporary claims or the need of claims is for few user. E.g: Giving temporary access to few users etc.
But, if the claim is related to all users, then it is better to keep the info in user table and add it as a claim using IClaimsTransformation.
For simplicity and learning purpose, here we'll add claim to the AspNetUseClaims table to test our Claims Based Authorization. Let's add a claim named DOB with Value '1969-01-01' for a user. Again adding DOB to the claims table is not the recommended approach.
Add Claim Check
Claim based authorization checks are declared via Policies. We've to specify claims checks using Policies. Let's add a policy having claim check. We've used a static AgeHelper.CalculateAge(string dob) to calculate age, which is simply calculating and returing age based on the DOB.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Is21OrOverOnly", policy =>
policy.RequireAssertion(context => context.User.HasClaim(c =>
c.Type == "DOB" && AgeHelper.CalculateAge(c.Value) >= 21
)
)
);
});
Let's apply the policy to our controller.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace EmployeeManagement.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "Is21OrOverOnly")]
public class RolesController(RoleManager<IdentityRole> roleManager) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAll()
{
return Ok(await roleManager.Roles.ToListAsync());
}
}
}
Test the implementation
In the above implementation, the user which is satisfying the above policy requirement will be able to access the Controller action method. User having claim as DOB and is satisfying the age criteria will be able to access the endpoint.
Adding a simple Claim check
We can also use policy.RequireClaim() for a simple claim check. Here is an example:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("HRMember", policy =>
policy.RequireClaim("Department", "HR")
);
});Above will simply validate the claim value against its name. However we can pass list of string as value. In this scenario only one value must match with the user's claim value.
Conclusion
Claims Based Authorization is useful many places where we want to provide access based on user attributes. Role is also added as a claim in the ClaimsPrincipal. Not every authorization check is done via role. Claim Based Authorization is one example.

Comments
Post a Comment