如何使用角色在 Web Api 中进行过滤

How to filter in webApi using roles

我有这个控制器

public class WorkController : ControllerBase
{
    [Authorize(Roles = "admin")]
    [HttpPost("something/add")]
    public async Task<IActionResult> Add()
    {
        //add
    }
    [Authorize(Roles = "admin,support")]
    [HttpGet("something/get")]
    public async Task<IActionResult> Get()
    {
        //get
    }
}

授权工作正常,但我认为它可以做得更好,我只是想问问是否有类似的东西可以过滤 Roles 并允许它基于 http 动词,比如发件人的角色是admin,他可以访问所有方法,如果角色是support,他只能访问Get方法.使这个全局化会很棒,因为我有很多方法

I just wanna ask if there's something like i could filter the Roles and allow it based on the http verb, like if the role of the sender is admin, he could access all methods, and if the role is support, he could only access the Get methods.

当然可以。首先,您需要创建规则:

public class GlobalVerbRoleRequirement: IAuthorizationRequirement
{
    public bool IsAllowed(string role, string verb)
    {
        // allow all verbs if user is "admin"
        if(string.Equals("admin", role, StringComparison.OrdinalIgnoreCase)) return true;
        // allow the "GET" verb if user is "support"
        if(string.Equals("support", role, StringComparison.OrdinalIgnoreCase) && string.Equals("GET",verb, StringComparison.OrdinalIgnoreCase)){
            return true;
        };
        // ... add other rules as you like
        return false;
    }
}

(如果您有更多规则,您可能需要进一步自定义 IsAllowed(role, verb)

并告诉 ASP.NET 核心如何使用 AuthorizationHandler 处理此规则:

public class GlobalVerbRoleHandler : AuthorizationHandler<GlobalVerbRoleRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public GlobalVerbRoleHandler(IHttpContextAccessor httpContextAccessor)
    {
        this._httpContextAccessor = httpContextAccessor;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, GlobalVerbRoleRequirement requirement)
    {
        // check whether the user has required roles for current verb
        var roles = context.User.FindAll(c => string.Equals(c.Type,ClaimTypes.Role)).Select(c => c.Value);
        var verb= _httpContextAccessor.HttpContext?.Request.Method;
        if(string.IsNullOrEmpty(verb)){ throw new Exception($"request cann't be null!"); }
        foreach(var role in roles){
            if(requirement.IsAllowed(role,verb)){
                context.Succeed(requirement); 
                return Task.CompletedTask;
            }
        }
        context.Fail();
        return Task.CompletedTask;
    }
}

最后别忘了在启动时注册相关服务:

services.AddHttpContextAccessor();
services.AddScoped<IAuthorizationHandler, GlobalVerbRoleHandler>();
services.AddAuthorization(opts =>{
    opts.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddRequirements(new GlobalVerbRoleRequirement())
        .Build();
});

现在每个 [Authorize] 也会根据当前 HTTP Verb 自动检查 Role

[Authorize]
public class WorkController : ControllerBase
{

    [HttpPost("something/add")]
    public async Task<IActionResult> Add()
    {
        //add
    }

    [HttpGet("something/get")]
    public async Task<IActionResult> Get()
    {
        //get
    }
}