【问题标题】:Role-based read/write access in .NET Core Web API.NET Core Web API 中基于角色的读/写访问
【发布时间】:2018-09-04 08:43:27
【问题描述】:

我想创建这种访问权限的层次结构,在我们下降时继承权利:

已通过身份验证:只能发出 GET 请求。
已通过角色“员工”进行身份验证:还具有对特定控制器的写入权限。
身份验证 w/角色“管理员”:在每个控制器上都有读/写。

到目前为止,我只遇到过自定义策略需要某些角色的解决方案。然后将此策略应用于控制器:[Authorize(Roles = "Role")]。这个解决方案的问题是我必须将“只读”策略添加到所有 HttpGet 操作,即使我全局需要管理员角色。

我想消除有人忘记或意外删除控制器上的[Authorize] 属性的可能性。

我正在寻找一种解决方案,其中全局设置的策略允许我根据角色和 http 动词限制访问。有点像我们在设置 CORS 时所做的,伪代码如下:

var getPolicy = new RoleBasedPolicyBuilder()
    .AnyRole().AllowHttpMethod("GET");

var employeePolicy = new RoleBasedPolicyBuilder()
    .Role("employee").AllowController(EmployeeController);

var writePolicy = new RoleBasedPolicyBuilder()
    .Role("admin").AllowAnyHttpMethod();

o.Filters.Add(new AuthorizeFilter(getPolicy));
o.Filters.Add(new AuthorizeFilter(employeePolicy));
o.Filters.Add(new AuthorizeFilter(writePolicy));

【问题讨论】:

    标签: asp.net-core authorization asp.net-core-webapi


    【解决方案1】:

    编辑:

    如果您具有读取权限的角色,第一个解决方案也可以使用。 通过阅读文档,我唯一能想到的其他解决方案是实现接口IAsyncAuthorizationFilter

    public class TestAuthorizeHandler : IAsyncAuthorizationFilter
    {
        private readonly string[] methodsThatDoNotRequireSpecialRoles =
        {
            "OPTIONS",
            "HEAD",
            "GET",
        };
    
        private const string PostMethod = "POST";
    
        public Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            // we don't need users to be authenticated for routes that contain this filter
            if (context.Filters.Any(filter => filter is IAllowAnonymousFilter))
            {
                return Task.CompletedTask;
            }
    
            var requestMethod = context.HttpContext.Request.Method;
    
            // we don't want to check authorization for the given methods
            if (methodsThatDoNotRequireSpecialRoles.Any(method => method == requestMethod))
            {
                return Task.CompletedTask;
            }
    
            if (requestMethod == TestAuthorizeHandler.PostMethod && context.HttpContext.User.IsInRole("MyWriteMethodRoles"))
            {
                return Task.CompletedTask;
            }
    
            context.Result = new ForbidResult();
            return Task.CompletedTask;
        }
    }
    

    现在在你的 ConfigureServices(...) 函数中添加一个 mvc 过滤器

    public void ConfigureServices(IServiceCollection services)
    {
       services.AddMvc(options => {
          options.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder()
                        .RequireAuthenticatedUser()
                        .Build()));
          options.Filters.Add(typeof(TestAuthorizeHandler));
       }
    }
    

    另请参阅https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies,了解更多可能可行的方案。

    之前的建议:

    添加一个全局过滤器,要求用户在您的ConfigureService(...) 函数中获得授权

    public void ConfigureServices(IServiceCollection services)
    {
       services.AddMvc(options => {
          options.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder()
    .AddRequirements(new RolesAuthorizationRequirement(new []{ "role1", "role2"}))
                        .RequireAuthenticatedUser()
                        .Build()));
       });
    }
    

    现在每个控制器路径都需要使用您的角色之一进行授权。如果您需要某个端点具有特定角色,您仍然需要设置它。如果您不想在某些路由中使用它,您只需将 [AllowAnonymous] 添加到控制器或特定端点函数即可。

    【讨论】:

    • 但是我只确保用户必须具有角色才能具有 R/W 访问权限。我仍然需要在每个[HttpGet] 请求中添加[AllowAnonymous]
    • 好像我误解了这个问题,以为你也有阅读角色:)现在正在寻找其他东西作为解决方案。
    • 目前正在测试这个解决方案。现在我得到了 403,即使在成功使用await context.HttpContext.AuthenticateAsync("Bearer") 进行身份验证之后也是如此。 ChallengeResult("Bearer"); 应该返回什么?因为现在我只是得到一个带有单个字符串的列表:“Bearer”在其中......
    • 如果您仍然收到 403,我认为您不会像 new ClaimsPrincipal(new ClaimsIdentity(claims, "Bearer"));但它可能会有所不同。您必须深入研究它才能使其与您的身份验证系统一起使用。你在用什么?身份服务器?
    • 带有 Azure AD 的 JWT 不记名令牌。
    猜你喜欢
    • 2020-09-24
    • 2019-07-07
    • 2019-07-05
    • 2021-03-19
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    相关资源
    最近更新 更多