Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Combine/Compose Authorization Handlers in ASP.Net Core?

How do I re-use AuthorizationHandlers to compose a composite requirement of the two handlers?

  • RequirementA with one Handler IsAllowedAccessToA : AuthorizationHandler<RequirementA>
  • RequirementB with one Handler IsAllowedAccessToB : AuthorizationHandler<RequirementB>
  • RequirementA_OR_B where if it meets IsAllowedAccessToA or IsAllowedAccessToB it succeeds

I have resources that are only accessible to RequirementA and the same for RequirementB. I also have resources that are available to A or B.

I can't figure out how to do this without duplicating IsAllowedAccessToA and IsAllowedAccessToB handlers

This article helps but is not exactly the same use case.

like image 760
spottedmahn Avatar asked Mar 08 '23 10:03

spottedmahn


2 Answers

try this:

you're requirement class is like this:

public class PermissionRequirement : IAuthorizationRequirement
{
    public PermissionRequirement(string permission)
    {
        this.Permission = permission;
    }

    public string Permission { get; }
}

and the handler should be like this:

public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
    private readonly IPermissionProvider _permissionProvider;

    private readonly IUserProvider _userProvider;

    public PermissionAuthorizationHandler(IPermissionProvider permissionProvider, IUserProvider userProvider)
    {
        // permissionProvider is a class that has a function called hasClaim, with bool return value that takes user id and claim as input arguments and realize weather the user id has access to the controller or not
        this._permissionProvider = permissionProvider;

        // userProvider, return the id of current user
        this._userProvider = userProvider;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        var hasClaim= await this._permissionProvider.HasClaim(this._userProvider.GetUserId(), requirement.Permission)
                                .ConfigureAwait(false);

        if (hasClaim) context.Succeed(requirement);
        else
            context.Fail();
    }
}
like image 184
Milad jalali Avatar answered Apr 28 '23 03:04

Milad jalali


There isn't a super clean way to express a policy as either of two other policies.

But you could write this imperatively as a helper method that authorizes against both policies, you wouldn't be able to do this via Authorize, but you could just call this where needed:

async Task<bool> IsAllowedAccessToAOrB(ClaimsPrincipal user, IAuthorizationService auth, object resource) {
      return await auth.AuthorizeAsync(user, resource, "PolicyA") || await auth.AuthorizeAsync(user, resource, "PolicyB")
}
like image 20
Hao Kung Avatar answered Apr 28 '23 04:04

Hao Kung