【问题标题】:MVC Core AuthorizationMVC 核心授权
【发布时间】:2016-11-22 19:26:23
【问题描述】:

我正在将 MVC Core 用于一个需要解决以下问题的网站。

假设我有两个组 GroupA 和 GroupB,这些组有一些实体。一个实体要么属于 GroupA 要么属于 GroupB - 但不能同时属于两者。为了保护这些实体的更新,我定义了以下策略:

AuthorizationOptions.AddPolicy("UpdateEntityInGroupAPolicy", policy =>
{
    policy.RequireClaim("ClaimThatAllowsUpdatingEntityInGroupA");
});

此政策将确保想要更新 GroupA 中的实体的用户拥有声明 ClaimThatAllowsUpdatingEntityInGroupA。可以为 GroupB 创建一个类似的策略,声明为 ClaimThatAllowsUpdatingEntityInGroupB。

此外,假设 GroupA 有一个 id 为 5 的实体,GroupB 有一个 id 为 10 的实体。如果给定用户(拥有声明 ClaimThatAllowsUpdatingEntityInGroupA,但没有声明 ClaimThatAllowsUpdatingEntityInGroupB)正在更新 url 上 id 为 5 的实体:

http://example.com/entity/5/update

我现在如何确保用户不只是将 url 中的 5 更改为 10 并实际更新 GroupB 中 id 为 10 的其他实体?

我希望我对这个问题很清楚,并感谢您的帮助:)

【问题讨论】:

    标签: asp.net-core authorization


    【解决方案1】:

    如果你想使用Authorize 属性,你不能这样做,因为授权过滤器不知道你的实体。因此,对于您的情况,Resource Based Authorization 似乎是正确的选择。

    首先假设你的实体是这样的:

    public class YourEntity
    {
        public int Id { get; set; }
        public string Group { get; set; }
        //...
    }
    

    实现基于资源的授权

    创建需求:

    public class UpdateRequirement : IAuthorizationRequirement
    {
    }
    

    为需求和实体创建授权处理程序

    public class YourEntityAuthorizationHandler : AuthorizationHandler<UpdateRequirement, YourEntity>
       {
           public override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       UpdateRequirement requirement,
                                                       YourEntity resource)
           {
               if(resource.Group == "GroupA" &&
                  context.User.HasClaim("ClaimThatAllowsUpdatingEntityInGroupA"))
               {
                   context.Succeed(requirement);
               }
               else if(resource.Group == "GroupB" &&
                  context.User.HasClaim("ClaimThatAllowsUpdatingEntityInGroupB"))
               {
                   context.Succeed(requirement);
               }
               return Task.CompletedTask;
           }
       }
    

    最后在你的控制器逻辑中使用它:

        public async Task<IActionResult> Update([FromServices]IAuthorizationService authorizationService, int id)
        {
            var entity= _entityRepository.Get(id);
    
            if (entity == null)
            {
                return new NotFoundResult();
            }
    
            if (await _authorizationService.AuthorizeAsync(User, entity, new UpdateRequirement()))
            {
                return View(entity);
            }
            else
            {
                return new ChallengeResult();
            }
        }
    

    另见@blowdart 的example

    【讨论】:

    • 感谢您的详细回答。我也可以在其他地方阅读相同的方法,例如this excellent page here。我认为这就是要走的路。谢谢:)
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2020-02-16
    • 2018-03-13
    • 1970-01-01
    • 2022-10-13
    • 2020-06-11
    • 2017-06-26
    • 1970-01-01
    相关资源
    最近更新 更多