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


94

我对claimsin 的使用是全新的,ASP.NETIdentity并且想了解使用in 的最佳实践Roles and/or Claims

读完所有这些之后,我仍然有诸如...的问题。

问:我们不再使用角色吗?
问:如果可以,为什么仍提供角色?
问:我们应该只使用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();
}

1
因此,我现在正面临着相同的问题,如何解决它以及如何在应用程序中实现权限?
罗阿,2016年

Answers:


77

角色是一个象征性类别,可将共享相同级别安全权限的用户收集在一起。基于角色的授权要求首先标识用户,然后确定为用户分配的角色,最后将这些角色与被授权访问资源的角色进行比较。

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

Microsoft文档

创建身份后,可以分配一个或多个由受信任方发出的声明。声明是一个名称值对,表示对象是什么,而不是对象可以做什么。

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

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


6
我不认为这是完全正确的。我相信声明表明的是身份,而不是授权。他们被授权做的事情是分开管理的。也就是说,他们可能有一个声称其出生日期超过18岁的声明。该声明将传递给授权管理器,其中可能包含一条规则,内容为“如果他们超过18岁,则可以编辑资源X”,但是声明本身并不能说明他们可以/不能或无法访问的内容。角色和其他主张也是如此。声明表明您是谁,并被用来确定您可以做什么,但它们并不能直接告诉您
ChrisC

@ChrisC的支持文档来自ASP.NET Core中基于 Microsoft 基于声明的授权:“声明是一个名称值对,表示主题是什么,而不是主题可以做什么。”
DrGriff

@DrGriff感谢您提供该链接;我一直在问我所描述的准确性。我想我已经根据该链接澄清了答案。
Claies

29

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

巴里·多兰斯(Barry Dorrans)播放了一段精彩的解释性视频,谈到了使用声明而非角色的优势。他还指出,角色仍在.NET中以实现向后兼容。该视频非常有用地说明了声明,角色,策略,授权和认证的工作方式。

您可以在这里找到它:Barr Dorrans的ASP.NET Core授权


8

数十年来使用了各种身份验证和授权技术后,我当前的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");
    }
}

那么角色适合在哪里?

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

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


3

为了理解角色和声明之间的区别,您要面对角色的局限性并了解声明如何解决此问题,因此我给您提供了两种方案,以认识到角色无法解决此问题时声明的作用:

1-您的站点有两个模块(页面,服务等),第一个模块针对未成年人(18岁以下),另一个模块针对成人(18岁以上),您的用户身份具有生日声明

您需要针对此声明制定政策,以便每个模块的授权都将基于此值给出,如果用户的年龄超过18岁,那么他可以进入成人模块,且年龄不得早于该年龄

角色是布尔数据类型,您可以具有或没有角色角色没有恶意值

2-您的站点具有角色用户,您将不阻止用户访问而无需更改代码即可进行一些维护

在声明中,您可以创建UnderConstrain策略,如果真实用户无法查看页面,则为角色用户提供属性授权。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.