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)]