Finally, a library that improves role authorization in ASP.NET Core

Last Updated: September 14, 2021 | Created: August 10, 2021

In December 2018 I wrote the first article in the series called “A better way to handle authorization in ASP.NET Core” which describe an approach to improving how authorization (i.e., what pages/feature the logged in user can access) in ASP.NET Core. These articles were very popular, and many people have used this authorization/data key approaches in their applications.

Back in 2018 I didn’t think I could produce a library for people to use, but I have finally found a way to build an library, and it’s called AuthPermissions.AspNetCore (shorten to AuthP library in these articles). This open-source library implements most of the features described in the “A better way to handle authorization” series, but the library will work with any ASP.NET Core authentication provider and now supports JWT Tokens.

NOTE: At this time this article was written the AuthPermissions.AspNetCore library is/was in preview (1.0.0-preview) and I am looking for feedback before taking the library to full release. Please look at the roadmap discussion page for what is coming. Also, the preview some features won’t work on a web app running multiple instances (called scale-out on Azure).

This first article is focused on the improvements the AuthP library provides to using “Roles” to manage what feature users can access, but the library contains a number of other useful elements. The full list of articles is shown below:

  • Finally, a library that improves role authorization in ASP.NET Core (this article).
  • Improving security when using JWT Tokens in ASP.NET Core (VIDEO)
  • Managing the roles and permissions of your ASP.NET Core users (coming soon).
  • Simplifying the building of a multi-tenant architecture with ASP.NET Core (coming soon).

TL;DR; – summary

  • The AuthPermissions.AspNetCore library has three main features:
    • Implements an improved Role authorization system (explained in this article).
    • Implements a JWT refresh token for better JWT Token security (article 2 coming soon)
    • Includes an optional a multi-tenant database system (article 4 coming soon)
  • The AuthPermissions.AspNetCore library can work with
    • Any ASP.NET Core authentication provider.
    • Either Cookie authentication or JWT Token authentication
  • This article focuses on AuthP’s improved “Roles / Permissions” approach, which allows you to change a Role without having to edit your application. Each user has a list or Roles, each Role containing one or more enum Permissions.
  • When the user logs in the AuthP library finds all the Permissions in all the Roles that the user has. These Permissions are packed into a string and added as a “Permissions” claim into the Cookie authentication or the JWT Token.
  • The AuthP’s HasPermission attribute / method will only allow access if the current user has the required Permission.
  • See other articles or the AuthP’s documentation for more information.
  • You can see the status of the AuthP library via the Release Notes document in the repo.

Setting the scene – How the AuthP library improves Roles authorization in ASP.NET Core

If you not familiar with ASP.NET’s authentication and authorization features, then I suggest you read the ”Setting the Scene” section in the first article in the A better way to handle authorization” series.

Back in the ‘old days’ with ASP.NET MVC the main way to authorize what a user can access was by using the Authorize attribute with what are called “Roles” – see the code below, which only lets a user with either the “Staff” or “Manager” Role to access that method/page.

[Authorize(Roles = "Staff,Manager")]
public ActionResult Index()
{
    return View(MyData);
}

ASP.NET Core kept the Roles approach but added the more powerful policy-based approach. But I found both approaches to have limitations:

  • Limitations of the ASP.NET Core Roles approach
    • The main limitation of the ASP.NET Core Roles is that authorization rules are hard coded into your code. So, if you want to change who can access a certain pages/Web APIs, you have to edit the appropriate Authorize attributes and redeploy your applicatios.
    • In any reasonably sized application, the Authorize attributes can get long and complicated, e.g.  [Authorize(Roles = “Staff, SalesManager , DevManage, Admin, SuperAdmin”)]. These are hard to find and maintain.
  • Limitations of the ASP.NET Core Roles policy-based approach
    • It very versatile, but I have to write code for each policy, which are all slightly different. And in a real application you might end up writing a lot of policy code.

From my point of view “Roles” are a useful concept for users, typically a user (human or machine) has a Role, or a few Roles, like SalesManager with maybe with an additional FirstAider role. Think of Roles as “Use Cases for users”.

But “Roles” are not a useful concept when defining what ASP.NET Core page/feature the user can access. That’s because for some feature you need fine-grained control, for instance a different access level for display, create, and update of sales information. For this a use what I call “Permissions”, for example you I might have SalesRead, SalesSell, SaleReturn, Permissions where the “Sales person” Role only have the SalesRead, SalesSell Permissions, but the” Sales manage” Role also has the SaleReturn Permission.

The AuthP’s approach says that “users have Roles, and your code uses Permissions to secure each page/WebAPI”. The AuthP’s Roles a number of benefits:

  1. No more deploying a new version of your application when you want to change what a Role can do – the AuthP’s Role/Permissions mapping is now in a database which admin people can change.
  2. The Permissions are declarative, just like the [Authorize] attribute (e.g. [HasPermission(MyPermissions.SalesSell)]) which makes it easier to maintain.
  3. You can have broad Permissions, e.g. NoticeBroadAccess (covering create, read, update, and delete), or fine-grained Permissions like SalesRead, SalesSell, SalesSellWithDiscount, SaleReturn for individual actions/pages.

NOTE: The AuthP’s Roles are different from the ASP.NET Core Roles – that’s why I always refer to “AuthP’s Roles” so that its clear which type of Role I am talking about.

How to use the AuthP’ library with its Roles and Permissions

So, let’s look at the various code you need in your ASP.NET Core application to use the AuthP’s Roles/Permissions system. Starting at the Permissions and working up the parts are:

  1. Defining your Permissions using an Enum
  2. Using these Permissions in your Blazor, Razor, MVC or Web API application
  3. Configuring the AuthP library in ASP.NET Core’s ConfigureServices method.
  4. Managing the user’s AuthP Roles and what Permissions are in each Role.

1. Defining your Permissions

The Permissions could be strings (just like ASP.NET Roles are), but in the end I found a C# Enum was best for the following reasons:

  • Using an Enum means IntelliSense can prompt you as to what Enum names you can use. This stops the possibility of typing an incorrect Permission name.
  • Its easier to find where a specific Permission is used using Visual Studio’s “Find all references”.
  • You can provide extra information to an Enum entry using attributes. The extra information helps the admin person when looking for a Permission to add to a AuthP’s Role – see the section on defining your Permission Enum.
  • I can use the Enum value: In the end I defined an enum with a ushort value (giving 65534 values), which can be stored efficiently in a (Unicode) string. This is important because the Permissions needed to be held in a claim and if you ASP.NET Core’s Cookie Authorization then a cookie has a maximum size of 4096 bytes.

So, let’s look at an example from Example4 in the AuthP’s repo, which is an application that manages a shop stock and sales. I have only shown a small part of Permissions in this example, but it gives you an idea how you can decorate each Permission to provide more info and filtering to the admin user.

public enum Example4Permissions : ushort //Must be ushort to work with AuthP
{
    NotSet = 0, //error condition

    //Here is an example of very detailed control over the selling things
    [Display(GroupName = "Sales", Name = "Read", Description = "Can read any sales")]
    SalesRead = 20,
    [Display(GroupName = "Sales", Name = "Sell", Description = "Can sell items from stock")]
    SalesSell = 21,
    [Display(GroupName = "Sales", Name = "Return", Description = "Can return an item to stock")]
    SalesReturn = 22,

    [Display(GroupName = "Employees", Name = "Read", Description = "Can read company employees")]
    EmployeeRead = 30,

    //other Permissions left out… 
}

2. Using these Permissions in your Blazor, Razor, MVC or Web API application

AuthP can be used with any type of ASP.NET Core application, with three ways to check if the current user has a given permission.

2a. Using AuthP’s [HasPermission] attribute

For a ASP.NET Core MVC or Web API controller you can add the [HasPermission] attribute to an access method in a controller. Here is a example taken from Example2’s WeatherForecastController, which is Web API controller – see the first line.

[HasPermission(PermissionEnum.ReadWeather)]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
    //… other code left out
}

2b. Using AuthP’s HasPermission extension method

If you are using Blazor, or in any Razor file you can use the HasPermission extension method to check if the current ASP.NET Core’s User has a specific Permission. Here is an example taken from AuthP’s Example1 Razor Pages application

public class SalesReadModel : PageModel
{
    public IActionResult OnGet()
    {
        if (!User.HasPermission(Example1Permissions.SalesRead))
            return Challenge();

        return Page();
    }
}

The HasPermission extension method is also useful in any Razor page (e.g. User.HasPermission(Example.SalesRead)) to decide whether a link/button should be displayed. In Blazor the call would be @context.User.HasPermission(Example.SalesRead).

2c. Using the IUsersPermissionsService service

If you are using a front-end library such as React, Angular, Vue and so on, then your front-end needs to know what Permissions the current user has so that the front-end library can create method similar to option 2, the HasPermission extension method.

The IUsersPermissionsService service has a method called PermissionsFromUser which returns a list of the Permission names for the current user. You can see the IUsersPermissionsService service in action in Example2’s AuthenticateController.

3. Configuring the AuthP library in ASP.NET Core’s ConfigureServices method.

The AuthP library has a lot of methods and options to set it up. It will work with any ASP.NET Core authentication provider that returns the UserId as a string.  

The code below uses ASP.NET Core’s Individual Accounts authentication provider in an MVC-type application – the highlighted lines contain the configuration code to set up the

public void ConfigureServices(IServiceCollection services)
{
    //… other normal ASP.NET configuration code left out
    
    //This registers the AuthP library with your Permission Enum 
    services.RegisterAuthPermissions<MyPermissions>()
        //This sets up the AuthP’s database 
        .UsingEfCoreSqlServer(Configuration.GetConnectionString("DefaultConnection"))
        //This syncs AuthP to your ASP.NET Core authentication provider, 
        //In this example it’s the Individual Accounts authentication provider
        .RegisterAuthenticationProviderReader<SyncIndividualAccountUsers>()
        //This will ensure the AuthP’s database is created/migrated on startup
        .SetupAuthDatabaseOnStartup();
}

NOTE: There are many configuration parts to the AuthP’s library, and this shows a simple configuration appropriate for an existing application that is using ASP.Net Core’s Individual Accounts authentication. Please look at the AuthP startup documentation for a more detailed list of all the configuration options.

How the AuthP library works inside

The final part of this article gives you an overview of how the AuthP library works, mainly with diagrams. This should help you understand how AuthP library works.

When someone logs in some ASP.NET Core claims are built and stored in an the Authentication Cookie or in the JWT Token. The diagram shows the AuthP code in orange, with the blue part provided by ASP.NET Core and its authentication provider.

As you can see AuthP finds the user’s AuthP Roles and combine the Permissions in all the user’s AuthP Roles into a string (known as packed permissions), which becomes the Permissions claim’s value. This Permissions claim is stored in the Authentication Cookie or in the JWT Token.

This approach is a) very efficient as the Permission data is available as a claim (i.e., no database accesses needed), and b) a user’s AuthP Roles can be changed without needing to re-deploy your application.

NOTE: Normally the Permissions are only calculated when someone logs in, and any change to the Users’ AuthP Roles would only change by logging out and back in again. However, there are features in AuthP that can periodically re-calculate the user’s Roles/Permissions. I talk about this in this section of the document explaining how JWT Token refresh works.

The second part is what happens when a logged-in user wants to access a Page, Web Api etc. Because AuthP library added a Permissions claim to the Authentication Cookie / JWT Token the ASP.NET Core ClaimsPrincipal User claims will contain the Permissions claim.

When an [HasPermission(MyPermissions.SalesSell)] attribute is applies to a ASP.NET Core controller or Razor Page is calls a policy-based service that the AuthP library has registered. This Permission policy allows access to the method / page if the “MyPermissions.SalesSell” Permission is found in the User’s Permissions claim’s string. Otherwise, it redirects the user to either the login page or an Access Denied page, if already logged in (or for Web API it returns HTTP 401, unauthorized, or HTTP 403, forbidden).

Conclusion

This first article gives you an overview of the AuthP’s most important, that is the ability to change what a Role can do via an admin page instead of the ASP.NET Core Roles where a change requires you to edit your code and redeploy your application. In addition, the AuthP’s Permissions allow you to have very fine-gained access rules if you need it. Future articles will explain other features in the AuthP libraray.

The AuthP library is far from finished but I think it has the basics in it. The big limitation of the preview is that some features, like bulk loading on startup, only run on a single instance of the web app (i.e. no scale out). My plan is to solve that in the non-preview version of the AuthP library

I have put out a preview version to get some feedback. I have set up a roadmap discussion for you to see what I am planning and getting your suggestions and help. Please have a look at the library and add your comments suggestions to the roadmap discussion.

Happy coding!

5 4 votes
Article Rating
Subscribe
Notify of
guest
8 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
fatihozturk
7 days ago

Thank you for sharing this article and opensource solution. Authentication and authorization processes  are always time-consuming and an issue that needs attention. We have a subject that is open to development. QR Code sign in, passwordless (for example shazam), select with tenant.

JACQUES MICHEL HACHE
JACQUES MICHEL HACHE
24 days ago

Does it work with MySql?

Adam David Collings
25 days ago

Thank you for creating and sharing this. It is very timely for me, especially the multi-tenant stuff.

Jeff Bowman
Jeff Bowman
1 month ago

Great job, thanks.

Can this be used in an MVC5 application?