![]() |
| Policy Based Authorization in ASP.NET Core |
In this article we'll learn about Policy Based Authorization and how to implement in ASP.NET Core Web API. In previous articles we discussed about differnt types of Authorization. We also discussed about Role based Authorization and Custom authorization. Here are the links to those articles.
- Introduction to Authorization in ASP.NET Core
- Role Based Authorization in ASP.NET Core Web API
- Custom Authorization in ASP.NET Core Web API
What is Policy Based Authorization?
A policy is a combination of one or more requirements. In Custom Authorization, we create requirement and requirement handler to authorize an endpoint or resource. We can add multiple requirements (e.g. adding multiple requirement attribute) to an endpoint for authorization. But, this will became diffcult to manage. Meaning, we've to add the same requirements repeatedly to all the endpoint where we want to use the same authorization condition.
Policy Based Authorization helps to manage all these in a centralized way. We can create a policy including all these requirements and instead of adding all the requirement attribute into an endpoint we can simply add the policy.
For e.g. in previous article we've created a requirement attribute named as AllowedEmailAuhorize for our custom authorization. There we've added this attribute on the controller to authorize an endpoint based on the user email. Here is the previous implementation:
using EmployeeManagement.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace EmployeeManagement.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AllowedEmailAuthorize("admin@mail.com")]
public class RolesController(RoleManager<IdentityRole> roleManager) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAll()
{
return Ok(await roleManager.Roles.ToListAsync());
}
}
}
Note: We're not adding the definition of requirement attribute and implementation of the handler for the requirement here. We've already discussed this in Custom Authorization in ASP.NET Core. Please go through this article if you need more information on Requirment and Requirement Handler and how it is being used for Authorization.
Now, we'll implement this custom authorization using Policy.
Register a policy in program.cs
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AllowAdminsOnly",
policy =>
policy.Requirements.Add(new AllowedEmailAuthorizeAttribute("admin@mail.com")));
});
Here we've registered a policy to the service collection. Now, we can use this policy wherever required in our controller or endpoints. Let's use this policy in the above controller instead of adding the requirement directly to our RoleController.
Apply policy to the endpoint
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace EmployeeManagement.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "AllowAdminsOnly")]
public class RolesController(RoleManager<IdentityRole> roleManager) : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAll()
{
return Ok(await roleManager.Roles.ToListAsync());
}
}
}
We've applied policies to controller using [Authorize(Policy = "AllowAdminsOnly")]. This will allow only the user which email id is admin@mail.com.
Add multiple requirements to policy
We can add multiple requirements to a policy. All of the requirements under a policy are evaluated on AND basis. Meaning, all of the requirement must succeed to authorize an user. Here is the example of multiple requirements.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CustomPolicy",
policy =>
{
policy.Requirements.Add(new CustomAuthorizeAttribute1());
policy.Requirements.Add(new CustomAuthorizeAttribute2());
}
);
});
Create a policy requiring role
when we apply role based authorization to an endpoint using Authorize attribute, for e.g [Authorize(Roles = "Admin")], authorization middleware behind the scene creates a policy and adds a Requirement and Handler for the requirement and then evaluate the policy for authorization check. Each authorization check is done via policy.
We can also create a policy for role check. Here is an example.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AllowAdminsOnly",
policy => policy.RequireRole("Administrator"));
});
Add the policy to the endpoint with authorize endpoint like Authorize[Policy = "AllowAdminsOnly"]. This will authorize the endpoint based on the policy requirement. We can pass array of role here as well. In case of multiple roles the policy will evaluate the authorization for roles on OR basis.
Policy that requires authenticated users
We can create a policy that requires user to be authenticated to be able to access an endpoint. Here is an example.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AuthenticatedUserOnly", policy => policy.RequireAuthenticatedUser());
});
The simple [Authorize] attribute added to controller to the same thing as well. Internally, it creates a policy with the above approach. However, we can add our own policy to rquire authenticated user for accessing an endpoint.
Pass a Func to create a policy
We can pass a Func to define a policy. RequireAssertion() accepts type of Func<AuthorizationHandlerContext, bool> to configure a policy. Here is an example.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("GateEntry",
policy => policy.RequireAssertion(context => context.User.HasClaim(c =>
(c.Type == "GatePassId" || c.Type == "TemporaryGatePassId")
&& c.Issuer == "https://microsoftsecurity"))
);
});
This policy will allow the endpoint to access if the user has the above GatePassId or TemporaryGatePassId.
Benefits of using a policy
- Centralized logic: Each policy is registered in startup with its requirement. The policy is used in the endpoint to authorize. Change in requirement in start up will update the authorization check for each endpoint.
- Easy Maintainance: Due to it's centralized logic, it is easy to update the requirement.
- Increases Reusability: We can create a policy and use it in multiple endpoints with same requirements.
- Combine multiple rules: Unlike role based authorization it can only check for roles. But here we can combine multiple rules inside a policy for accessing an enpoint.
- Clean Approach: As the logic resides in one place, it will be considered as clean.
Conclusion
Here we got to know how to implement Policy Based Authorization. Under the hood, Authorization Middleware always creates a policy and adds the requirement when there is no policy defined while authorizing an endpoint. When we're simply using the [Authorize] attribute in an endpoint, authroization middleware under the hood creates a policy and adds a RequireAuthenticatedUser requirement to that policy and then evaluates the authorization.
Policy based authorization helps us keep the authorization logic in centralized place. It increases resuability.
I hope you liked this article. Please share your feedback or suggestion for improvements in comments.

Comments
Post a Comment