How to Create a Custom Authorize Attribute in ASP.NET Core

When implementing an API using ASP.NET Core, there’s often a need to authorize that API’s users. Your system might be organized into several separate areas, which provide access to different resources and actions. It’s very likely that not all users are allowed to use all of those areas. Within a single area, a design might require restricted access to data entities themselves. There are many ways to implement such authorization, one of them being declaring custom authorization attributes on controller methods/actions or on controllers as a whole.

In ASP.NET Core MVC, authorization is performed using the AuthorizeAttribute class. Here’s a simple example using role-based authorization:

[Authorize(Roles = "Admin,Moderator")]
public class AdminController : Controller
{
    // ... 
}

Users with the Admin or the Moderator role will have access to the actions in the AdminController.

While there’s nothing wrong with this, and it gets the job done, the "Admin,Moderator" string—like you might imagine—is a good recipe for a typo. So let’s move the role names to a set of string constants:

public static class RoleConstants
{
    public const string Admin = "Admin";
    public const string Moderator = "Moderator";
    // more roles
}
C#

The AdminController now becomes:

[Authorize(Roles=RoleConstants.Admin+","+RoleConstants.Moderator)]
public class AdminController : Controller
{
    // ... 
}

Not ideal, I know. Unfortunately, we can’t use interpolated strings like $"{RoleConstants.Admin},{RoleConstants.Moderator}" with attributes.

This is a good example where extending the AuthorizeAttribute class makes sense. Since we’re trying to make it easier to call for role-based authorization on a controller or action, let’s create a custom AuthorizeByRoleAttribute:

/// <summary>
/// Specifies that the class or method that this attribute is applied to requires role-based authorization. <br />
/// To authorize users with either role A or role B, use:
/// <code>
/// [AuthorizeByRole("A", "B")]
/// </code>
/// To only authorize users with both role A and role B, use:
/// <code>
/// [AuthorizeByRole("A")] <br />
/// [AuthorizeByRole("B")]
/// </code>
/// </summary>
public class AuthorizeByRoleAttribute : AuthorizeAttribute
{
    public MyAuthorizeAttribute(params string[] roles)
    {
        Roles = String.Join(",", roles);
    }
}

We can use it as follows:

[AuthorizeByRole(RoleConstants.Admin, RoleConstants.Moderator)]
public class AdminController : Controller
{
    // ... 
}

Conclusion

Using custom attributes is a very practical and clean way to implement a custom authorization system for your ASP.NET Core API. It reduces the amount of redundant code and allows developers to make the permissions as granular as needed. By simple adjustments to Swagger (if it’s used), the front-end developers can also easily see which permissions an API method requires.

Agnes Berry