ChatGPT解决这个技术问题 Extra ChatGPT

ASP.NET 身份中角色与声明的最佳实践

我对在 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 ?

C
Claies

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

相反,声明不是基于组的,而是基于身份的。

来自 Microsoft documentation

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

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

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


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

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

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

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


链接坏了。可在此处访问视频:youtube.com/watch?v=dDroEVdAqKM
p
pixelda

几十年来使用了各种身份验证和授权技术,我当前的 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 的一部分,并且尚未找到它们的等价物。再次感谢。
A
Ahmed Suror

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

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

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

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

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

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


P
Prisoner ZERO

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

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

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

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

使升级项目更容易/更快?

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

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

问:我们应该一起使用角色和声明吗?

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

而且您不必编写自己的属性,您应该为此使用策略,因为这是较新框架的方式。如果您需要自己的属性,那么您“做错了”,只需创建自己的需求(处理程序),这就是整个“新”政策的全部内容。在当前框架中,ClaimAuthorize 属性甚至不再可用。