Applying Policy-based Authorization in ASP.NET Core

Applying Policy-based Authorization in ASP.NET Core
Photo Credit: unsplash/maurosbicego

In this post, we will learn how to implement authorization by applying policy-based authorization in ASP.NET Core. In previous versions of ASP.NET MVC such as version 5.2 it was possible to implement a custom authorize attribute and override AuthorizeCore(HttpContextBase httpContext). But in ASP.NET Core this is no longer possible, the recommended approach by Microsoft ASP.NET Core team is to use the declarative role and a rich policy-based model.

Enabling Policy-based Authorization in ASP.NET Core

The main idea behind the new approach is to make use of the [Authorize] attribute to assign a "policy" (example: [Authorize(Policy = "YourCustomPolicy")]. Authorization Policies are the backbone of the ASP.NET Core Authorization Framework. Even when you use claim-based or role-based authorization, you are actually using Policy-based Authorization. A Policy defines a set of rules, that the user must satisfy in order to access a resource in the application. Usually, the policy is defined in Program.cs using the AddAuthorization method in the services collection of the WebApplicationBuilder:
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireClaim("Admin"));

});

Here is another example on how to define a policy with single claim and value:

options.AddPolicy("AdminOnly", policy => policy.RequireClaim("Permission", "Admin"));

You can also chain multiple Claims together as shown below. The SuperAdmin policy requires user to have Permission claim with Value Admin and separate Admin claim. The user must satisfy both conditions:

options.AddPolicy("SuperAdmin", 
        policy => policy.RequireClaim("Permission", "Admin")
                        .RequireClaim("Admin"));
Here are some additional examples on the different types of policies that we can define in ASP.NET Core:
  • Policy only for Authorized Users
options.AddPolicy("AuthenticatedUsers", policy => policy.RequireAuthenticatedUser());
  • Policy using a Role
options.AddPolicy("AdminRole", policy => policy.RequireRole("AdminRole"));
  • Policy using a User Name
options.AddPolicy("JohnOnly", policy => policy.RequireUserName("John"));

Applying the Policy-based Authorization in ASP.NET Core

We apply the policy using the Authorize attribute and we apply it to the header of the action in the controller. The following code applies the AdminOnly policy to the action Index: 
[Authorize(Policy = "AdminOnly")]
public IActionResult Index()
{
    return View();
}
 
The policy design is a great addition to the ASP.NET Core. However, there are some cases where we need to apply authorization for CRUD actions, it will be difficult to defines these policies and to cover all cases. and the ASP.NET Security Core team should be commended for its introduction. That said, it isn't well-suited for all cases. While the ASP.NET Core Security team recommends never creating custom authorization solution, in some cases this may be the most suitable option with which we can cover all the cases in our applications.

The following is an implementation of the interface IAuthorizationFilter, it provides a simple way to express a claim requirement for a given controller or action:

public class ClaimRequirementAttribute : TypeFilterAttribute
{
    public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
    {
        Arguments = new object[] {new Claim(claimType, claimValue) };
    }
}

public class ClaimRequirementFilter : IAuthorizationFilter
{
    readonly Claim _claim;

    public ClaimRequirementFilter(Claim claim)
    {
        _claim = claim;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
        if (!hasClaim)
        {
            context.Result = new ForbidResult();
        }
    }
}

public class HomeController : Controller
{
    [ClaimRequirement(MyClaimTypes.Permission, "CanReadView")]
    [HttpGet]
    public IActionResult Index()
    {
        return View();
    }
}

The code in this post can be applied to an ASP.NET Core MVC web app. We will explore how to apply authorization in a Razor Pages web app in another post.

Post a Comment

Previous Post Next Post