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"));
- 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
[Authorize(Policy = "AdminOnly")]
public IActionResult Index()
{
return View();
}
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.