只授权ASP.NET Core中的某些Http方法

pba*_*nis 1 c# asp.net-authorization asp.net-core asp.net-core-identity

我想对控制器上的所有操作都要求一个策略,并且对HTTP“编辑方法”(POST,PUT,PATCH和DELETE)的所有调用都需要第二个策略。也就是说,编辑方法应同时要求两个策略。由于实现要求,以及保持代码DRY的愿望,我需要将后者策略应用于控制器级别,而不是在所有操作方法上都重复使用。

举一个简单的例子,我有一个PeopleController,我也有两个许可权,分别实现为Policy ViewPeopleEditPeople。现在我有:

[Authorize("ViewPeople")]
public class PeopleController : Controller { }
Run Code Online (Sandbox Code Playgroud)

如何添加EditPeople策略/权限,使其“堆叠”且仅适用于编辑动词?

我遇到了两个似乎都是很痛苦的问题:

  • 您不能在AuthorizeAttribute AFAIK中指定一个以上的AuthorizeAttribute或一个以上的策略。
  • 您无法在自定义AuthorizationHandler中访问该请求,因此我无法检查HttpMethod进行检查。

我尝试使用自定义Requirement和AuthorizationHandler解决前者,如下所示:

public class ViewEditRolesRequirement : IAuthorizationRequirement
{
    public ViewEditRolesRequirement(Roles[] editRoles, Roles[] viewRoles)
        => (EditRoles, ViewRoles) = (editRoles, viewRoles);

    public Roles[] EditRoles { get; }
    public Roles[] ViewRoles { get; }
}

public class ViewEditRolesHandler : AuthorizationHandler<ViewEditRolesRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ViewEditRolesRequirement requirement)
    {
        if (context.User != null)
        {
            var canView = requirement.ViewRoles.Any(r => context.User.IsInRole(r.ToString()));
            var canEdit = requirement.EditRoles.Any(r => context.User.IsInRole(r.ToString()));
            if (context. // Wait, why can't I get to the bloody HttpRequest??
        }
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

……但是if (context.直到我意识到我无权访问请求对象之前,我的理解才达到了极限。

我唯一的选择是覆盖OnActionExecuting控制器中的方法,并在那里获得我的授权吗?我认为这至少是皱眉头的?

Sha*_*tin 5

您无法在自定义AuthorizationHandler中访问该请求,因此我无法检查HttpMethod ...

实际上,我们可以在AuthorizationHandler中访问Request。我们通过context.Resource使用as关键字强制转换来实现。这是一个例子:

services.AddAuthorization(config =>
{
    config.AddPolicy("View", p => p.RequireAssertion(context =>
    {
        var filterContext = context.Resource as AuthorizationFilterContext;
        var httpMethod = filterContext.HttpContext.Request.Method;
        // add conditional authorization here
        return true; 
    }));

    config.AddPolicy("Edit", p => p.RequireAssertion(context =>
    {
        var filterContext = context.Resource as AuthorizationFilterContext;
        var httpMethod = filterContext.HttpContext.Request.Method;
        // add conditional authorization here
        return true;
    }));
});
Run Code Online (Sandbox Code Playgroud)

您最多只能有一个AuthorizeAttribute...。

实际上,我们可以有多个AuthorizeAttribute。从文档中注意到,该属性具有AllowMultiple=true。这使我们可以“堆叠”它们。这是一个例子:

[Authorize(Policy="View")]
[Authorize(Policy="Edit")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    ...
}
Run Code Online (Sandbox Code Playgroud)