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

Asp.net mvc ASP.NET Identity中角色与声明的最佳实践,asp.net-mvc,roles,claims-based-identity,Asp.net Mvc,Roles,Claims Based Identity,我对ASP.NETIdentity中的声明的使用是完全陌生的,我想了解角色和/或声明使用的最佳实践 读了这么多之后,我仍然有一些问题,比如 问:我们不再使用角色了吗? 问:如果是,为什么仍然提供角色? 问:我们应该只使用索赔吗? 问:我们应该一起使用角色和声明吗? 我最初的想法是,我们“应该”一起使用它们。我将索赔视为其支持的角色的子类别 例如: 角色:会计 索赔:CanUpdateLedger、CanOnlyReadLedger、CandeletFromLedger 问:它们是相互排斥的吗?

我对
ASP.NETIdentity
中的
声明的使用是完全陌生的,我想了解
角色和/或声明使用的最佳实践

读了这么多之后,我仍然有一些问题,比如

问:我们不再使用角色了吗?
问:如果是,为什么仍然提供角色?
问:我们应该只使用索赔吗?
问:我们应该一起使用角色和声明吗?

我最初的想法是,我们“应该”一起使用它们。我将
索赔
视为其支持的
角色的子类别

例如:
角色:会计
索赔:CanUpdateLedger、CanOnlyReadLedger、CandeletFromLedger

问:它们是相互排斥的吗?
问:还是只进行索赔并“完全符合”您的索赔更好?
问:那么这里的最佳实践是什么?

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

[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();
}

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

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

发件人:

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

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


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

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

Barry Dorrans有一个很好的解释视频,讲述了使用声明胜过角色的优势。他还表示,角色仍在.NET中以实现向后兼容性。该视频非常详细地介绍了声明、角色、策略、授权和身份验证的工作方式


您可以在这里找到:

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

索赔用于所有授权。用户被分配了一个角色(可以有多个角色,但我不需要这个)-更多信息如下

按照惯例,使用ClaimsAuthorize属性类。由于大多数控制器操作都是CRUD,我在代码优先数据库生成中有一个例程,它迭代所有控制器操作,并为每个控制器操作属性Read/Edit/Create/Delete创建声明类型。例如,从

[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);
        }
那么角色在哪里合适呢

我有一个将角色链接到(默认)声明集的表。设置用户授权时,默认设置是为用户提供其角色声明。每个用户可以拥有比默认值更多或更少的声明。为了简化编辑,索赔列表将按控制器和操作(一行)显示,然后列出其他索赔。按钮与一点Javascript一起用于选择一组操作,以最小化选择索赔所需的“点击”。保存时,将删除用户声明并添加所有选定声明。web应用程序只加载一次声明,因此任何更改都必须在该静态数据中提示重新加载


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

要了解角色和索赔之间的区别,您必须面对角色的限制,并了解索赔是如何克服这些问题的,因此,我给您两个场景,以识别角色无法解决这些问题的索赔的威力:

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

您需要为此声明创建策略,以便根据此值授予每个模块的授权,如果用户的年龄超过18岁,则他可以进入成人模块,而不是在此年龄之前

角色是布尔数据类型,您可以拥有或不拥有该角色 这个角色没有什么价值观

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


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

因此,我现在面临同样的问题,您如何解决该问题,以及如何在应用程序中替代权限?我认为这不完全准确。我相信
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");
    }
}