代码之家  ›  专栏  ›  技术社区  ›  Fraze

最佳实践:自定义asp.net核心标识授权

  •  1
  • Fraze  · 技术社区  · 6 年前

    应用程序中的组件需要考虑以下授权项:

    • 角色
    • 位置
    • 分开
    • 实体(应用程序中的特定组件)。比如“管理新闻”)

    public int assignId; //key
    public int userId;
    public int roleId;
    public int? locationId;
    public int? divisionId;
    public int? entityId;
    

    真实世界场景

    • 角色为“Admin”且位置为“Indy”的用户“Joe”对“Indy”位置中的每个实体都有权限。
    • 用户“Blow”,角色为“Admin”,位置为“Indy”,部门为“IT”,对“Indy”中的每个“IT”实体都有权限
    • 用户“Joe”的角色为“Admin”,位置为“Chicago”,部门为“Safety”,实体为“News”,只能在芝加哥的安全部门发布新闻。(除上述关于乔和印第的规定外)

    那么,我的问题是?

    使用asp.net core 2.1标识处理此类授权规则/策略的最佳方法是什么?添加“loc”和“indy”这样的声明?

    谢谢你的帮助!!!!!!!

    1 回复  |  直到 6 年前
        1
  •  3
  •   itminus    6 年前

    早期版本的ASP.NET使用 接近。然而,在这种情况下 基于索赔 倾向于接近。因为我们很难确定允许哪个角色访问资源。

    • Adam :Role=全局管理员
    • Joe
    • Blow :Admin;Location=Indy;Division=IT;

    这个 AspNetUserClaims 表将用户的索赔记录为bleow:

    ID |用户ID |索赔类型|索赔值|

    ----|:------|:----------|:----------:|

    4 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |角色|管理员

    5 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |位置|印地

    6 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |位置|芝加哥

    8 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |分区|安全

    9 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |实体|新闻

    10 | b60c7b75-e31b-4856-ba98-666d013c8201 |角色|管理员

    11 | b60c7b75-e31b-4856-ba98-666d013c8201 |位置|印地

    15 | b60c7b75-e31b-4856-ba98-666d013c8201 |部门| IT

    如你所见 基于索赔

    services.AddAuthorization(opts=> {
        // ... other policy ...
        // ...
        opts.AddPolicy("Check:Role|Location|Division|Entity", pb=>
            pb.RequireAssertion(async context=> await RldeChecker.Handle(context) )
        );
    })
    

    这个 Checker.Handle(上下文) 下面是一个简单的静态方法,它接收 授权handlercontex 作为参数,检查用户是否可以访问某些特定资源。

    为了更清楚,我们可以添加 策略检查器/ RldeChecker 分类:

    public class RldeChecker
    {
        // ...
    
        public static async Task<bool> Handle(AuthorizationHandlerContext context) {
    
            var user = context.User;
            // bypass all checks
            if (user.HasClaim("Role","Global Admin" )) { return true; }
            try
            {
                // retrieve the user claims
                var userLocation = user.FindFirst("Location")?.Value;
                var userDivision = user.FindFirst("Division")?.Value;
                var userEntity = user.FindFirst("Entity")?.Value;
                // retrieve the resource that the user want to access at runtime
                var resource = (Dictionary<string, string>)context.Resource; 
                var targetLocation = resource["Location"];
                var targetDivision = resource["Division"];
                var targetEntity = resource["Entity"];
    
                // check for local admin
                // ...
            }
            catch {
                return false;
            }
            return false;
        }
    }
    

    当我们想在一个action方法中授权用户时,我们可以简单地插入 IAuthorizationService 核对 authService.Authorize(user,resource,"Check:Role|Location|Division|Entity") . 此外,基于索赔的方法允许我们以服务的方式使用它,然后我们可以根据需要将它注入到任何地方,例如,根据当前用户的位置/部门/实体显示不同的内容:

    var resource = new Dictionary<string, string>() {
        { "Location","Indy"},
        { "Division","IT"},
        { "Entity","News"},
    };
    var x = await this._authorizationService.AuthorizeAsync(User, resource, "Check:Role|Location|Division|Entity");
    if (x.Succeeded)
    {
        return View();
    }
    else
    {
        return new ForbidResult();
    }