如何在ASP.Net Core中组合/合成授权处理程序?

5
我如何重复使用AuthorizationHandlers来组合这两个处理程序的需求
  • RequirementA有一个处理程序IsAllowedAccessToA:AuthorizationHandler<RequirementA>
  • RequirementB有一个处理程序IsAllowedAccessToB:AuthorizationHandler<RequirementB>
  • RequirementA_OR_B,如果满足IsAllowedAccessToAIsAllowedAccessToB则成功

我有一些只能通过RequirementA访问的资源,RequirementB也是一样。 我还有一些可供A或B使用的资源。

我无法在不重复IsAllowedAccessToAIsAllowedAccessToB处理程序的情况下完成此操作。

这篇文章有帮助,但并不完全适用于该使用情况。

4个回答

3

请尝试以下方法:

您的需求类似于这样:

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

    public string Permission { get; }
}

处理程序应该像这样:

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();
    }
}

2

没有一种非常清晰的方法来将一个策略表达为另外两个策略之一。

但你可以编写一个命令式的帮助方法,对这两个策略进行授权,虽然你不能通过Authorize实现这一点,但你可以在需要时调用它:

async Task<bool> IsAllowedAccessToAOrB(ClaimsPrincipal user, IAuthorizationService auth, object resource) {
      return await auth.AuthorizeAsync(user, resource, "PolicyA") || await auth.AuthorizeAsync(user, resource, "PolicyB")
}

1
实际上,您指向的文章已经给出了所有答案。您需要做的唯一事情就是以这样的方式定义处理程序,使它们可以用于不同的要求,即使它们变得通用。稍后,您将只需使用每个要求的不同类型参数将它们注册为服务。

因此,您的处理程序将类似于:

public class IsAllowedAccessToA<T>
    : AuthorizationHandler<T> where T : IAuthorizationRequirement
{
}

您将注册它们以用于复合要求,例如:

services.AddSingleton<IAuthorizationHandler, IsAllowedAccessToA<RequirementA_OR_B>>();
services.AddSingleton<IAuthorizationHandler, IsAllowedAccessToB<RequirementA_OR_B>>();

这应该可以满足您的需求。

1

假设你的RequirementA_OR_B由两个需求组成,例如:

public class RequirementA_OR_B : IAuthorizationRequirement
{
    public RequirementA RequirementA { get; set; }
    public RequirementB RequirementB { get; set; }
}

然后您可以按照以下方式创建组合处理程序:
public class RequirementA_OR_BHandler : AuthorizationHandler<RequirementA_OR_B>
{
    private RequirementAHandler _requirementAHandler;
    private RequirementBHandler _requirementBHandler;

    public RequirementA_OR_BHandler(/* Whatever is needed by either handlers*/)
    {
        // note: the dependency injection framework might directly inject both handlers, but I didn't check
        _requirementAHandler = new RequirementAHandler();
        _requirementBHandler = new RequirementBHandler();
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RequirementA_OR_B requirement)
    {
        // create a dummy context with both requirements
        var requirements = new IAuthorizationRequirement[]
        {
            requirement.RequirementA,
            requirement.RequirementB,
        };

        var dummyContext = new AuthorizationHandlerContext(requirements, context.User, null);
        await _requirementAHandler.HandleAsync(dummyContext);
        await _requirementBHandler.HandleAsync(dummyContext);

        // if either A or B succeeds, the number of pending requirements will decrease
        if (dummyContext.PendingRequirements.Count() < 2)
            context.Succeed(requirement);

        await Task.FromResult(true);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接