ASP.NET Core 2.0 Authorization

Problem

How to implement authorization in ASP.NET Core.

Solution

Starting from the previous project on authentication, setup some dummy users and their claims.

We’re creating the following users with permissions as below.

UserMemberFree MemberPaid MemberOver 18New Release
Guest     
FreeYY   
PaidY Y Y
Over18Y YY 

In Startup, we’ll configure authorization policies, which will use claims to fulfill policies, i.e., authorize users.

Some of these simply check the existence of a claim and its value, however, last two require some special business logic. Framework provides IAuthorizationRequirement and AuthorizationHandler for this purpose.

Add a Controller to apply the authorization policies to.

Discussion

Authorization is about deciding permissions users have and resources they can access. In ASP.NET Core, this is achieved by first assigning claims to the user and then based on those claims defining policies to determine user permissions.

Claims

A claim is just a name/value pair. During the authentication process you assign them to ClaimsIdentity, which in turn is assigned to ClaimsPrincipal. Claims contain information about the user e.g. their email, birth date, driving license number, passport number etc.

Key to remember about claim is that they are what the user “is” and not what the user can do.

Policy

A policy is about what the user is allowed to do, it’s the permission rule. Policies are added when configuring authorization services in Startup class. Some rules are based on the existence of claims while others on more complicated business logic.

In the code above, being a member and paid member simply check the existence of a certain claim. For more complicated rules, you create a requirement and a handler for it. In the code above age and new release, rentals are examples of this (full code listing on GitHub).

Note

When multiple policies are applied to a controller/action, they form AND logical operation. In the code above, to access Over18 content (policy on action) you have to be a Paid Member too (policy on controller).

Requirements and Handlers

A requirement is a data class implementing a marker interface IAuthorizationRequirement. The requirement can have one or more handlers; classes inheriting from AuthorizationHandler type.

Handlers can also be resource based i.e. take in a custom type. This is useful when authorization is based on data dynamically coming from the database. For instance, when a movie is loaded from the database, it will have a flag to indicate whether it’s a new release or not. Our requirement handler can use this resource (Rental object) to check against user claims,

Now we can inject IAuthorizationService in our controller and use it to check this policy, passing in our model.

Views

Injecting IAuthorizationService into views allows us to control UI elements using the policies.

Note

Showing and hiding of UI elements is not a replacement of [Authorize] attribute or using IAuthorizationService in controllers, users could access actions via URL!?

Migrating from ASP.NET Core 1.1

When converting the sample from ASP.NET Core 1.1 to 2.0 I had to make one simple change. The AuthorizeAsync() method on IAuthorizationService returns AuthorizationResult in 2.0 whereas in 1.1 it returned a bool. I had this code in 1.1 and it worked,

Source Code

GitHub