Home > Software engineering >  Custom authorization in ASP.NET Core with enum roles
Custom authorization in ASP.NET Core with enum roles

Time:09-30

I'm trying to add custom authorization to an ASP.NET Core 6 Razor Pages app using Policies. This example from one of the Microsoft people recommends implementing an IAuthorizationRequirement.

Here's the wrinkle: I need to use an enum for the roles that are listed in the Authorize attribute, such as [Authorize(RoleEnum = Role.SysAdmin | Role.Manager)], similar to how we could do in Framework with the [Flags] attribute.

I've written the following requirement based on Microsoft's own code and I've changed it to use enums:

public class RolesAuthorizationRequirement: AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationRequirement
{
    public RolesAuthorizationRequirement(IEnumerable<Constants.Role> allowedRoles)
    {
        if (allowedRoles == null)
        {
            throw new ArgumentNullException(nameof(allowedRoles));
        }

        if (allowedRoles.Count() == 0)
        {
            throw new InvalidOperationException("No roles provided.");
        }
        AllowedRoles = allowedRoles;
    }

    public IEnumerable<Constants.Role> AllowedRoles { get; }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
    {
        if (context.User != null)
        {
            bool found = false;
            if (requirement.AllowedRoles == null || !requirement.AllowedRoles.Any())
            {
                // Review: What do we want to do here?  No roles requested is auto success?
                found = true;
            }
            else
            {
                found = requirement.AllowedRoles.Any(r => context.User.IsInRole(r.ToString()));
            }
            if (found)
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}

I tried adding it to services but it complains that it needs the roles in the c'tor of RolesAuthorizationRequirement:

options.AddPolicy("Authorize", 
    policy => policy.AddRequirements(new RolesAuthorizationRequirement()));

Based on this post, I'll need this as well:

services.AddSingleton<IAuthorizationHandler, MyRequirementHandler>();

What am I missing? How do you wire this all up? Thanks.

CodePudding user response:

You can try something much simpler. Create a custom AuthorizeAttribute that converts the enum roles to comma separated string roles that the default authorization mechanism expects:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public CustomAuthorizeAttribute(Constants.Role roleEnum)
    {
        Roles = roleEnum.ToString().Replace(" ", string.Empty);
    }   
}

// assuming you have a Role enum similar to this:

public static class Constants
{
    [Flags]
    public enum Role
    {
        User = 1,
        SuperUser = 2,
        Admin = 4,
        SuperAdmin = 8
    }
}

Usage:

// instead of:
[Authorize(Roles = "User,Admin")]
// you can do:
[CustomAuthorize(Constants.Role.User | Constants.Role.Admin)]
  • Related