DEV Community

Karthik Chintala
Karthik Chintala

Posted on • Originally published at coderethinked.com on

Role-based Authorization in ASP.NET Core

What is role-based authorization?

As the name says, role-based authorization authorizes a user based on the role defined to the user.

Creating roles and users in ASP.NET Core with Identity

For this article, I’ve created a new ASP.NET Core app in .NET 6 with Individual Accounts as the Authentication type, which will create the roles, users, and other tables in the local database.

Here are the user and roles tables. I’ve added a few users and roles for our blog post.

roles and users
roles and users

Configuring role-based authorization in program.cs or startup.cs

Let’s see how we can use the role-based authorization in the asp.net core web app.

In the Program.cs file, we have the following line indicating the default identity is added to the application (this is added to my project by default because I’ve created a brand new one with Individual Accounts)

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
Enter fullscreen mode Exit fullscreen mode

We will add .AddRoles<IdentityRole>() (The IdentityRole class is part of Microsoft.AspNetCore.Identity) to the line which then becomes this.

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();
Enter fullscreen mode Exit fullscreen mode

And we’ve to register useAuthorization() between UseRouting and UseEndpoints otherwise, we might run into the following issue.

Configure your application startup by adding app.UseAuthorization() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(…), the call to app.UseAuthorization() must go between them

Decorating controllers and Razor pages for Role-based authorization

Setting the Roles property on the Authorize attributes is how we set the role-based authorization.

Ex: [Authorize(Roles = "Admin")]

For controllers, we can decorate the controller class like this

[Authorize(Roles = "Admin")]
public class HomeController : Controller
{
  [Route("index")]
  public IActionResult Index()
  {
      return View();
  }
}

Enter fullscreen mode Exit fullscreen mode

User having access invoking the Index action will see the below page

user having access to role
user having access to role

The user who does not have access to the Admin role receives the following access denied error.

user does not have access to role
user does not have access to role

Or we can have the Authorize on the action methods too.

[Authorize(Roles = "SuperUser")]
[Route("time")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());
Enter fullscreen mode Exit fullscreen mode

The user having a superuser role sees the current time on the Time action.

user have access
user has access to superuser role

A user without a superuser role sees the following accessing the time action.

user has no access to super user
user has no access to superuser

That’s how we add role-based authorization to the controllers.

Similarly, we can add the authorizations to the razor page. But, we cannot add an Authorize attribute on the page handler methods.

Here is the warning if we tried to add the Authorize attribute on the page handler methods.

“MVC1001 ‘AuthorizeAttribute’ cannot be applied to Razor Page handler methods. It may be applied either to the Razor Page model or applied globally.”

cannot have authorize on the razor page handler methods
Error when decorating authorize attribute over the Razor Page handler methods

How to apply multiple roles

To apply an OR between the roles to a single action we have to separate the roles by a comma

[Authorize(Roles = "SuperUser, Admin")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());
Enter fullscreen mode Exit fullscreen mode

The time action is accessible to users who have either SuperUser or Admin roles

To apply an AND between the roles, we stack the Authorize attribute on the action/controller.

[Authorize(Roles = "SuperUser")]
[Authorize(Roles = "Admin")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());
Enter fullscreen mode Exit fullscreen mode

Now, the time action is accessible only to the users who have both SuperUser and Admin as their roles.

Using policy-based roles

We can also combine multiple roles using policies and attach it to our controller/action/pages.

This has to be done in the Program.cs before we do the builder.Build() step

builder.Services.AddAuthorization(options => { 
  options.AddPolicy("SuperUserRights", policy => policy.RequireRole("Admin", "SuperUser", "BackupAdmin")); 
});
Enter fullscreen mode Exit fullscreen mode

Applying this policy with [Authorize(Policy = "SuperUserRights")] should work for us.

[Authorize(Policy = "SuperUserRights")]
public IActionResult Time() => Content(new TimeOnly().ToLongTimeString());
Enter fullscreen mode Exit fullscreen mode

References

The post Role-based Authorization in ASP.NET Core appeared first on Code Rethinked.

Top comments (0)