Resource-Based Authorization in ASP.NET Core

In this article, we will show you how to implement Resource-based authorization in ASP.NET Core. In Resource-based authorization, we inject the Authorization Service in the controller or Razor Page. We then call the AuthorizeAsync method to run an authorization check.

Resource-Based Authorization

The authorization policies that we built in the previous tutorial depend on Authorize attribute. The Authorization middleware reads the Authorize attribute and runs the checks to see if it can authorize the user.

The Authorization middleware runs before data binding and before execution of the action method (or page handler). Hence it does not have access to the data (resources) on which the action method operates.

But, there are many use cases that exist, where we need to load resources first, before determining if we can allow the user to access those resources. The Attribute-based authorization mechanism does not handle such use cases.

For Example, we want to allow only the creator of the document to edit or delete it. The other users can only view the document. In this scenario, we need to load the document first. We will then check if the creator of the document is the same as the logged-in user. Only then we can allow users to access the document.

How to Create resource based Authorization

Resource-based on Authorization is an imperative authorization. Here we do not rely on the Authorize attribute, But we choose when to call the Authorization Service.

We do that by injecting the Authorization Service into our controller class. In the action method, we load the resource first. After that, we call the AuthorizeAsync method passing the resource to it along with the policy that we want to apply. Once the method returns the result, we check it and take appropriate action.

Writing a resource-based handler is very similar to creating custom policy-based authorization. We learned how to create a policy-based authorization in the previous tutorial.

To Create a Resource-based Authorization

  1. Create an Authorization Requirement. The Requirement class must inherit from the IAuthorizationRequirement
  2. Next, create Authorization Handlers. The class must AuthorizationHandler<SameAuthorRequirement, Document>
  3. Register the Authorization Handlers for DI
  4. Create a Policy using the Authorization Requirement
  5. Inject the Authorization Service in the controller class
  6. Call the AuthorizeAsync method, wherever you want to check for Authorization.

Resource based Authorization Example

We will continue from where we left from our last tutorial on Policy based Authorization

Create Authorization Requirement

Create a class SameAuthorRequirement in the Authorization folder, which will act as a requirement for our policy.

A Requirement class must implement IAuthorizationRequirement from the Microsoft.AspNetCore.Authorization namespace. IAuthorizationRequirement does not contain any methods or properties. Hence we do not need to implement anything.

Authorization/SameAuthorRequirement.cs

Create Authorization Handler

Our Next task is to create an Authorization handler for the above requirement. The authorization handler contains the logic to determine if the requirement is Valid.

An Authorization Requirement can contain more than one Authorization Handlers

Create DocumentAuthorizationHandler in the Authorization folder.

The handlers must inherit from the AuthorizationHandler<TRequirement, TResource>. It has one method HandleRequirementAsync, which we must implement in our handler class.

Note that in policy-based Authorization, we inherited from AuthorizationHandler<TRequirement>. That is the only difference between resource-based implementation Vs policy-based implementation

The HandleRequirementAsync method gets the context, requirement & resource as the parameter. The context class has User (ClaimPrincipal) object.

In the code, we check to see if the CreatedUserID of the Product (resource) is the same as that of the logged-in user. If true return Succeed.

Authorization/DocumentAuthorizationHandler.cs

Registering the Handlers

Register the handler in the ConfigureServices method of the startup class..

Create the Policy based on Requirement

Using the Authorization Service

We want to limit access to the Edit method to the user who created the product. Open the MVCProductsController

First, we inject the IAuthorizationService in the constructor.

In the Edit method, first get the Product from the back end.

Call the method AuthorizeAsync with User, Product and policy name. The AuthorizeAsync invokes the DocumentAuthorizationHandler with the given Product.

DocumentAuthorizationHandler matches the UserId of the Product with the UserID of the logged-in user. If they match return Sucess.

We check if the authorization has passed from the variable result.Succeeded. If the authorization fails, then check if the user is authenticated. If not then redirect the user to the login screen else redirect to the access denied page.

Finally, last important point. Remember to update CreatedUserID with the currently logged-in user in the Create method. Also, remove CreatedUserID from the forms.

Now, run the application.

Create two users. Log in using one user and create a Product. Now log out and try to edit the product using another user. You should see the access denied page.

Resource based Authorization example in ASP.NET Core

Reference

Leave a Comment

Your email address will not be published.

Scroll to Top