首页 > 解决方案 > 如何使用角色在 webApi 中进行过滤

问题描述

我有这个控制器

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
    }
}

授权工作正常,但我认为它可以做得更好,我只是想问一下我是否可以过滤角色并根据 http 动词允许它,比如如果发件人的角色是admin,他可以访问所有方法,如果角色是support,他只能访问 Get 方法。让这个全球化会很棒,因为我有很多方法

标签: c#authorizationasp.net-core-webapi

解决方案


我只想问是否有类似我可以过滤角色并根据http动词允许它的东西,比如如果发件人的角色是管理员,他可以访问所有方法,如果角色是支持,他只能访问获取方法。

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

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 Core 如何使用 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();
});

现在everyone[Authorize]也会根据当前的HTTP动词自动检查角色。

[Authorize]
public class WorkController : ControllerBase
{

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

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

推荐阅读