【问题标题】:Best Practices for Roles vs. Claims in ASP.NET IdentityASP.NET 身份中角色与声明的最佳实践
【发布时间】:2015-09-06 17:53:34
【问题描述】:

我对在ASP.NETIdentity 中使用claims 完全陌生,并且想了解使用Roles and/or Claims 的最佳实践。

读完这么多,我还有一些问题……

问:我们不再使用角色了吗?
问:如果是这样,为什么仍然提供角色?
问:我们应该只使用声明吗?
问:我们应该同时使用角色和声明吗?

我最初的想法是我们“应该”一起使用它们。我将Claims 视为他们支持的Roles 的子类别。

例如:
角色:会计
声明:CanUpdateLedger、CanOnlyReadLedger、CanDeleteFromLedger

问:它们是否旨在相互排斥?
问:还是只进行索赔并“完全符合”您的索赔要求更好?
问:那么这里的最佳做法是什么?

示例:同时使用角色和声明
当然,你必须为此编写自己的属性逻辑......

[Authorize(Roles="Accounting")]
[ClaimAuthorize(Permission="CanUpdateLedger")]
public ActionResult CreateAsset(Asset entity)
{
    // Do stuff here

    return View();
}

示例:完全限定您的声明

[ClaimAuthorize(Permission="Accounting.Ledger.CanUpdate")]
public ActionResult CreateAsset(Asset entity)
{
    // Do stuff here

    return View();
}

【问题讨论】:

  • 那么,我现在面临同样的问题,您如何解决它以及如何在应用程序中对权限进行 subRole ?

标签: asp.net-mvc roles claims-based-identity


【解决方案1】:

角色是一个符号类别,它将共享相同级别安全权限的用户聚集在一起。基于角色的授权需要首先识别用户,然后确定用户被分配到的角色,最后将这些角色与被授权访问资源的角色进行比较。

相比之下,声明不是基于组的,而是基于身份的。

来自Microsoft documentation

创建身份时,可能会为其分配一个或多个由受信任方发布的声明。声明是一个名称值对,它表示主题是什么,而不是主题可以做什么。

安全检查稍后可以根据一个或多个声明的值确定访问资源的权利。

可以同时使用这两种类型,或者在某些情况下使用一种类型,在其他情况下使用另一种类型。这主要取决于与其他系统的互操作以及您的管理策略。例如,经理管理分配给某个角色的用户列表可能比管理分配了特定声明的用户更容易。声明在 RESTful 场景中非常有用,您可以将声明分配给客户端,然后客户端可以呈现声明以进行授权,而不是为每个请求传递用户名和密码。

【讨论】:

  • 我认为这并不完全准确。我相信声明表明身份,而不是授权。他们被授权做的事情是分开管理的。也就是说,他们可能有一个声明,其出生日期表明他们已超过 18 岁。此声明将传递给授权管理器,其中可能包含一条规则,即“如果他们超过 18 岁,他们可以编辑资源 X”,但声明本身并没有表明他们可以/不能做什么或访问。角色和其他声明也是如此。声明表明您是谁,并用于确定您可以做什么,但它们不会直接告诉您
  • @ChrisC 的支持文档来自 Microsoft 的 Claims-based authorization in ASP.NET Core:“声明是一个名称值对,它代表主题是什么,而不是主题可以做什么。”
  • @DrGriff 感谢您提供该链接;一段时间以来,我一直在质疑我给出的描述的准确性。我想我现在已经根据该链接澄清了答案。
【解决方案2】:

正如@Claies 完美解释的那样,声明可能更具描述性,并且是一种深入的角色。我认为它们是您的角色 ID。我有一个健身房ID,所以我属于会员角色。我也在上跆拳道课,所以我为他们申请了跆拳道身份证。我的申请需要声明一个新角色以符合我的会员权利。相反,我有我所属的每个组类的 id,而不是许多新的成员类型。这就是为什么声明更适合我。

有一个很棒的关于 Barry Dorrans 的解释视频,讲述了使用声明而不是角色的优势。他还指出,角色仍然在 .NET 中以实现向后兼容性。该视频对声明、角色、政策、授权和身份验证的工作方式提供了非常丰富的信息。

你可以在这里找到它:ASP.NET Core Authorization with Barr Dorrans

【讨论】:

【解决方案3】:

几十年来使用了各种身份验证和授权技术,我当前的 MVC 应用程序使用以下方法。

声明用于所有授权。用户被分配一个角色(多个角色是可能的,但我不需要这个) - 更多内容如下。

按照惯例,使用 ClaimsAuthorize 属性类。由于大多数控制器操作都是 CRUD,因此我在代码优先数据库生成中有一个例程,它迭代所有控制器操作并为读取/编辑/创建/删除的每个控制器操作属性创建声明类型。例如。来自,

[ClaimsAuthorize("SomeController", "Edit")]
[HttpPost]

为了在 MVC 视图中使用,基控制器类呈现视图包项

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // get user claims
            var user = filterContext.HttpContext.User as System.Security.Claims.ClaimsPrincipal;

            if (user != null)
            {
                // Get all user claims on this controller. In this controler base class, [this] still gets the descendant instance type, hence name
                List<Claim> claims = user.Claims.Where(c => c.Type == this.GetType().Name).ToList();

                // set Viewbag with default authorisations on this controller
                ViewBag.ClaimRead = claims.Any(c => c.Value == "Read");
                ViewBag.ClaimEdit = claims.Any(c => c.Value == "Edit");
                ViewBag.ClaimCreate = claims.Any(c => c.Value == "Create");
                ViewBag.ClaimDelete = claims.Any(c => c.Value == "Delete");
            }

            base.OnActionExecuting(filterContext);
        }

对于网站菜单和其他非控制器操作,我有其他主张。例如。用户是否可以查看特定的货币字段。

bool UserHasSpecificClaim(string claimType, string claimValue)
{
    // get user claims
    var user = this.HttpContext.User as System.Security.Claims.ClaimsPrincipal;

    if (user != null)
    {
        // Get the specific claim if any
        return user.Claims.Any(c => c.Type == claimType && c.Value == claimValue);
    }

    return false;
}

public bool UserHasTradePricesReadClaim
{
    get
    {
        return UserHasSpecificClaim("TradePrices", "Read");
    }
}

那么角色在哪里适合呢?

我有一个将角色链接到一组(默认)声明的表。设置用户授权时,默认是给用户他们角色的声明。每个用户可以拥有比默认更多或更少的声明。为了简化编辑,声明列表按控制器和操作(连续)显示,然后列出其他声明。按钮与一些 Javascript 一起使用来选择一组操作,以最大限度地减少选择声明所需的“点击”。保存时,将删除用户声明并添加所有选定的声明。 Web 应用程序仅加载一次声明,因此任何更改都必须提示重新加载此静态数据。

因此,经理可以选择每个角色中的哪些声明以及用户在将其设置为角色后拥有哪些声明以及这些默认声明。该系统只有少量用户,因此管理这些数据很简单

【讨论】:

  • 我一直试图让它在 .Net Core 3.1 中工作,我找不到对 ClaimsAuthorize 的引用。那是否不再存在,我必须创建自己的Attribute?谢谢
  • @RoLYroLLs 我认为他正在使用自定义授权属性 tut:(c-sharpcorner.com/article/…) 或使用 Thinktecture.IdentityModel.45 (github.com/nguyenbanguyen/Thinktecture.IdentityModel.45)
  • @iYazee6 感谢您的参考。我真的经历过第一次。但是,这两个参考都适用于 .Net Framework,而不是 .Net Core,并且在某些名称不属于 .Net Core 的情况下存在类似问题,并且尚未找到它们的等价物。再次感谢。
【解决方案4】:

要了解角色和声明之间的区别,您必须面对角色的限制并感受声明是如何解决这些问题的,所以让我给您两个场景来认识声明的力量,角色无法解决这些问题:

1- 您的网站有两个模块(页面、服务等),第一个模块适用于儿童(18 岁以下),另一个模块适用于成人(18 岁以上) 您的用户身份有生日声明

您需要为此声明创建一个政策,以便每个模块的授权都将基于此值,如果用户的年龄超过 18 岁,那么他可以进入成人模块,而不是在此年龄之前。

角色是布尔数据类型,您可以拥有或不拥有角色,它没有多值。

2- 您的站点具有角色用户,您希望阻止用户访问以进行一些维护而不更改代码。

在声明中,您可以创建一个 UnderConstrain 策略,如果该策略为 true,则用户无法查看页面,为角色用户授予属性授权。

【讨论】:

    【解决方案5】:

    在撰写此答案时,我们正处于“.NET 5.0”,而“.NET 6.0”指日可待。这是我对所见所闻的理解:

    问:我们不再使用角色了吗?

    是的,你不应该再使用角色了(至少不是你在以前的框架中使用的方式。

    问:如果是这样,为什么仍然提供角色?

    为了让升级项目更容易/更快?

    问:我们应该只使用声明吗?

    是的。但请务必查看@Jonathan Ramos 的答案中发布的视频。

    问:我们应该同时使用角色和声明吗?

    不,但您当然可以将角色放入声明中,但请务必升级您的项目以仅使用声明。

    你不应该写你自己的属性,你应该使用policy,因为这是新框架的方式。如果您需要自己的属性,那么您“做错了”,只需创建自己的 Requirement(handler) 即可,这就是整个“新”政策的全部内容。 在当前框架中,属性 ClaimAuthorize 甚至不再可用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-09
      • 2018-07-19
      • 1970-01-01
      • 2018-04-11
      • 2016-11-02
      • 2021-07-20
      相关资源
      最近更新 更多