Claims-Based Authorization and Policy-Based Authorization in ASP.NET Core

Role-based authorization in ASP.NET Core is simple but limited. Imagine you want to validate a user based on other         characteristics such as age or employee id? Of course, creating a role for each of these possibilities is not a         great solution.

Role-Based Authorization

If you’re familiar with roles in ASP.NET 4.x, you’ll find that the new features start from a familiar place. A user         can have several roles, and you define what roles are required to perform a specific action, or access to     particular     sections, within your application. You can define what roles are authorized to access a specific     action or     controller by using the [Authorize] attribute.

 [Authorize(Roles = "HeadTeacher, Teacher")] 
public class StudentReportController: Controller{
}
[Authorize(Roles = "Teacher")]
public class StudentAttendanceController: Controller{
}

Now the Policy-Based Authorization in ASP.NET Core

The policy-based model has three theories: policies, requirements, and handlers

1) A policy is composed of one or more requirements

2) A requirement is a collection of data parameters used by the policy to evaluate the user Identity

3) A handler is responsible for evaluating the properties of the requirements to determine if the user is authorized to access a specific resource

Let’s have looked the policy-based model here for a moment. If you were to do the previous example in a policy-based         format, you would follow the below steps.

Step 1 ) You have to register your policy in the ConfigureServices() method of the Startup class, as part of the authorization service configuration.

 public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();
  services.AddAuthorization(options =>{
    options.AddPolicy("RequireTeacherAll", policy => policy.RequireRole("HeadTeacher", "Teacher"));
    options.AddPolicy("RequireTeacherOnly", policy => policy.RequireRole("Teacher"));
  });
}

Step 2 ) Instead of specifying roles in the [Authorize] attribute, specify the policy you want to assert:

 [Authorize(Policy = "RequireTeacherAll")]
public class StudentReportController: Controller{

}  
[Authorize(Policy = "RequireTeacherOnly")]
public class StudentAttendanceController: Controller{

}

Step 3 ) That’s all! :)

You didn’t have to write any requirements or handlers, but the RequireRole() manage all the things. If you study more in details, check out the ASP.NET Core Security module source code.

Claims-Based Authorization via Policy-Based Authorization in ASP.NET Core

Role-based authorization in ASP.NET Core is simple but insufficient. Imagine you want to validate a user based on other characteristics such as age or employee id?

ASP.NET Core bases the identity of a user on claims. A claim is a key-value pair which represents characteristics of a subject, such as, name, age, email, etc.; and a subject can have multiple of these. A trusted party issues a claim and it tells you about who the subject is and not what a subject can do.

For example, let’s a project Management tool its have Employees, Client and other roles have to access the data   according to the requirement. You’d want to show the internal bugs report or cost report section. This only accessible to those users that have a company employee ID, and not to the Client or freelancers.

To do this, you’d have to register a new policy in the ConfigureServices() method of the Startup class, as part of the authorization service configuration:

 public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
 services.AddAuthorization(options =>{
    options.AddPolicy("EmployeesOnly", policy => policy.RequireClaim("EmpID"));
 });
}

 

In this case, the EmployeesOnly policy checks if the subject has a valid employee ID claim. You can restrict access to a controller by requiring this policy.

 [Authorize(Policy = "EmployeesOnly")]
public class ReportController : Controller{

}

Think More Complex Authorization with Custom Policies.

If you want to sell some age restricted product, Order Place action need to restrict by the age group. Then how we can manage this? Custom policies will help us solve the problem. Create a Custom Handler (AuthorizationHandler) with a minimum age requirement.

Step 1 ) Create Requirement inherit with 'IAuthorizationRequirement'

 public class AgeRequirement : IAuthorizationRequirement
{
  public int MinimumAge { get; set; }
  public AgeRequirement(int age)
  {
    MinimumAge = age;
  }
}

Step 2 ) Create AuthorizationHandler for validating the user age

 public class AgeHandler : AuthorizationHandler
{
 protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AgeRequirement requirement){
  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);
  var userAge = DateTime.Today.Year - dateOfBirth.Year;
  if (dateOfBirth > DateTime.Today.AddYears(-userAge)){
  userAge--;
  }    
if (userAge >= requirement.MinimumAge){
    context.Succeed(requirement);
  }
  return Task.CompletedTask;
 }
}

Step 3 ) Register your policy in the Authorization service configuration in the ConfigureServices() method of the Startup class. And register the handler to be injected on the framework

 public void ConfigureServices(IServiceCollection services) { 
  services.AddAuthorization(options => {   options.AddPolicy("AgeLimit", policy => policy.Requirements.Add(new AgeRequirement(18))); });     
  services.AddSingleton<IAuthorizationHandler, AgeHandler >(); 
 } 

Finally, you can add this policy in any Controller or action

 [Authorize(Policy = "Customer")]
public class CheckOutController : Controller {    

[Authorize(Policy = "AgeLimit")]
 public IActionResult PlaceOrder()
 {
   return View();
  }
}

Policy-Based Authorization is better than the role-based approach because the security code is self-documented and easy to use.