【问题标题】:best practice: customize asp.net core identity authorization最佳实践:自定义 asp.net core 身份授权
【发布时间】:2019-01-22 19:03:38
【问题描述】:

我对 asp.net 身份服务器相当陌生。我知道如何自定义 IdentityUser 实体和脚手架/覆盖身份 UI。鉴于这些情况,我正在寻找有关授权的高级操作方法和最佳实践:

应用程序中的组件需要考虑这些项目以进行授权:

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

来自一个班级网络表单背景,我倾向于这样定义角色:

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

真实世界场景

  • 角色为“Global Admin”的用户“Adam”拥有一切权限。
  • 角色“Admin”和位置“Indy”的用户“Joe”对“Indy”位置中的每个实体拥有权限。
  • 角色“Admin”、位置“Indy”和部门“IT”的用户“Blow”拥有“Indy”中每个“IT”实体的权限
  • 角色“Admin”和位置“Chicago”以及部门“Safety”和实体“News”的用户“Joe”只能发布芝加哥安全部门的新闻。 (除了上面关于 Joe 和 Indy 的规则)

那么,我的问题?

使用 asp.net core 2.1 身份处理此类授权规则/策略的最佳方法是什么?添加诸如“loc”/“indy”之类的声明?

我会设置自定义授权处理程序来检查声明吗?或者我会设置一个中间件表来处理关联,就像我在传统的网络表单时代一样?或者这种情况有最佳实践吗??

感谢您的帮助!!!!!!!

【问题讨论】:

    标签: c# asp.net-core asp.net-identity asp.net-core-2.0 claims-based-identity


    【解决方案1】:

    早期版本的 ASP.NET 使用基于角色的方法。但是,在这种情况下,新的Claims-Based 方法更受青睐。因为我们很难确定允许哪个角色访问资源。

    假设您在上面描述的三个用户和声明:

    • Adam:角色=全局管理员
    • Joe:角色=管理员;位置=印地&位置=芝加哥;师=安全;实体=新闻
    • Blow:管理员;位置=印地;部门 = IT ;

    AspNetUserClaims 表将用户的索赔记录为自爆:

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

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

    3 | 3ff3d2db-5a8f-4b01-99b5-fe46d22c240c |角色 |全局管理员

    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 |事业部 |它

    如您所见,Claim-Based方法的记录相当简单明了。当需要授权用户时,我们可以将用户的声明与策略进行比较:

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

    这里的 Checker.Handle(context) 是一个简单的静态方法,它接收 AuthorizationHandlerContex 的实例作为参数并检查用户是否可以访问某些特定资源。

    为了更清楚,我们可以添加一个 PolicyChecker/ 文件夹,并将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;
        }
    }
    

    当我们想在一个动作方法中授权用户时,我们可以简单地注入一个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();
    }
    

    【讨论】:

    • 非常感谢您非常彻底的回答。这不仅有帮助!!!!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2020-07-18
    • 2022-08-18
    相关资源
    最近更新 更多