Welcome to today’s post.
I will be discussing the implementation of imperative claims-based authorization handlers.
To be able to use claims-based authorization, we require the following prerequisites for the application security:
- Existing user accounts.
- Additional claims for each user account.
User accounts do NOT need to be in roles to utilize claims-based authorization. They can be used in isolation or in conjunction with role-based authorization.
In a previous blog I showed how to implement role-based imperative authorization.
In this blog I will show you how to use claims-based imperative authorization.
In an online library application, suppose we have a policy that prevents non-adults from loaning books that are for adults. Call this policy BookLoanAgeRestriction.
We also define a requirement for the minimum age, MinimumAgeRequirement.
Define the age requirement in a class as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
namespace BookLoan.Authorization
{
public class MinimumAgeRequirement: IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
}
In the startup ConfigureServices(), declare the policy as follows:
public void ConfigureServices(IServiceCollection services)
{
..
services.AddAuthorization(options =>
{
..
options.AddPolicy("BookLoanAgeRestriction", policy =>
{
policy.AddRequirements(
new MinimumAgeRequirement(18));
});
});
..
services.AddSingleton<IAuthorizationHandler,
BookLoanAgeRestrictionHandler>();
}
The age limit has been hard-coded for illustrative purposes, however it is better to configure this within your application.
Next, implement the claim policy handler as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
using BookLoan.Authorization;
using BookLoan.Models;
using BookLoan.Services;
namespace BookLoan.Authorization
{
public class BookLoanAgeRestrictionHandler : AuthorizationHandler<MinimumAgeRequirement, BookViewModel>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeRequirement requirement, BookViewModel resource)
{
if (!context.User.HasClaim(c =>
c.Type == ClaimTypes.DateOfBirth))
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth >
DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (resource.Genre.Contains("Adult"))
{
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
}
else
context.Succeed(requirement);
return Task.CompletedTask;
}
}
}
The handler method contains the following parameters:
context. This is the context of the user accessing the handler.
requirement. This is the age requirement (see above definition).
resource. This is an instance of the currently accessed book passed into the handler.
The handler does the following:
- Checks the user has a data of birth claim.
- Checks if the library book genre is of type “Adult” (we may have a better way to define adult books in the table). If the book is not of “Adult” type then pass authorization.
- Checks the age of the user is adult, if so then pass authorization.
To access the above handler, the code snip below can be used in a controller to test authorization using the above claim.
// GET: LoanViewModels/Create
[HttpGet("api/[controller]/Create/{id}")]
public async Task<IActionResult> Create(int id)
{
// use imperative authorization to check age restriction on library books.
BookViewModel bookView = await _bookService.GetBook(id);
if ((await _authorizationService.AuthorizeAsync(
User, bookView,
new MinimumAgeRequirement(18))).Succeeded)
{
LoanViewModel lvm = _loanService.CreateNewBookLoan(id);
lvm.LoanedBy = User.Identity.Name;
BookLoan.Views.Loan.CreateModel createModel = new
CreateModel(_context);
createModel.LoanViewModel = lvm;
return View(createModel);
}
else
{
return new ChallengeResult();
}
}
That’s all for today.
Hope this has been an informative post and you have learnt something useful.

Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.