答案 0 :(得分:225)
我将尝试展示如何从ASP.NET MVC上下文中的基于声明的访问控制中受益。
当您使用基于角色的身份验证时,如果您有创建客户的操作,并且您希望处于“销售”角色的人员能够这样做,那么您可以编写如下代码:
[Authorize(Roles="Sale")]
public ActionResult CreateCustomer()
{
return View();
}
后来,您意识到,有时候,来自“营销”角色的人员应该能够创建客户。然后,您更新您的Action方法
[Authorize(Roles = "Sale", "Marketing")]
public ActionResult CreateCustomer()
{
return View();
}
现在,您意识到,某些营销人员必须无法创建客户,但无法为营销人员分配不同的角色。因此,您被迫允许所有营销人员创建客户。
您发现了另一个问题,每当您决定允许营销人员创建客户时,您必须更新所有MVC操作方法授权属性,编译应用程序,测试和部署。几天后,您决定,而不是营销,但应允许其他角色执行任务,因此您在代码库中搜索并从“授权”属性中删除所有“营销”,并在“授权”属性中添加新角色名称...不是健康解决方案此时,您将意识到需要基于权限的访问控制。
基于权限的访问控制是一种为各种用户分配各种权限并检查用户是否有权在运行时从代码执行操作的方法。在为各种用户分配各种权限后,您意识到如果用户具有“Facebook用户”,“长时间用户”等属性,则需要允许某些用户执行某些代码。让我举个例子。假设您希望在用户使用Facebook登录时允许访问特定页面。现在,您是否会为该用户创建“Facebook”权限?不,'Facebook'听起来不像是一种许可。可以 ?相反,它听起来像是一种说法。与此同时,权限听起来也像索赔!因此,最好检查声明并允许访问。
现在,让我们回到基于声明的访问控制的具体示例。
您可以定义一组这样的声明:
“CanCreateCustomer”,“CanDeleteCustomer”,“CanEditCustomer”......等等。
现在,您可以像这样装饰您的Action方法:
[ClaimAuthorize(Permission="CanCreateCustomer")]
public ActionResult CreateCustomer()
{
return View();
}
(请注意,[ClaimAuthorize(Permission =“CanCreateCustomer”)]可能没有内置到MVC类库中,我只是作为一个例子展示,你可以使用一些具有这种属性类定义的类库)
现在,您可以看到,CreateCustomer操作方法将始终需要权限'CanCreateCustomer',它将永远不会更改或几乎不会更改。因此,在您的数据库中,您创建一个权限表(声明)和用户权限关系。在管理面板中,您可以为每个可以执行操作的用户设置权限(声明)。您可以将“CanCreateCustomer”权限(声明)分配给您喜欢的任何人,并且只允许用户能够创建客户,并且允许的用户将只能创建客户而不能创建其他任何内容(除非您为同一用户分配其他权限)。
此安全模型为您提供干净的代码练习。此外,当您编写Action方法时,您不必考虑谁可以使用此方法,而是始终可以确保使用此方法的任何人都将获得管理员提供的适当权限(声明)。然后,管理员可以决定谁将能够做什么。不是你作为开发人员。这就是你的业务逻辑如何与安全逻辑分离。
每当有人登录时,您的应用程序将检查该用户可用的任何权限,并且该权限(声明)集将作为当前登录用户的附加属性提供(通常声明集存储为已登录的cookie用户),因此您不必一直检查数据库中的权限集。最重要的是,如果您应用基于声明的访问而不是基于角色的访问,则可以更好地控制应用程序中的安全逻辑。实际上,角色也可以被视为一种声明。
如果您的应用程序是一个非常小的应用程序,其中只有两个角色:客户和管理员,除了他们在您的应用程序中的意图之外,客户不可能做任何其他事情,那么也许,基于角色的访问控制将达到目的,但随着应用程序的增长,您将在某个时刻开始感觉到需要基于声明的访问控制。
答案 1 :(得分:44)
我不完全同意Emran的回答
[Authorize(Roles="Sale")]
天真
问题是如何
[Authorize(Roles="CustomerCreator")]
与
不同 [ClaimAuthorize(Permission="CanCreateCustomer")]
如果两者同样好,我们为什么需要索赔?
我想因为
在上面的示例中,我们可以说“CustomerCreator”是“Asp.NETroleProvider”提供的“角色”类型的声明
索赔的其他例子。
“AAA”是由“MYExamSite.com”提供的“MYExamSite.Score”类型的声明
“Gold”是“MYGYMApp”提供的“MYGYM.Membershiptype”类型的声明
答案 2 :(得分:36)
接受的答案似乎将角色定位为一个钝器,声称是一个灵活的工具,但除此之外,它们看起来几乎相同。不幸的是,这种定位对索赔的概念不利,可能从根本上反映了对其目的的轻微误解。
角色存在且仅在隐式范围内有意义。通常,这是应用程序或组织范围(即Role = Administrator)。另一方面,索赔可以制作'任何人。例如,Google身份验证可能会产生包含用户"电子邮件"的声明,从而将该电子邮件附加到身份。 Google提出索赔,该应用程序选择是否理解并接受该声明。应用程序本身可能随后附加一个称为" authenticationmethod" (正如ASP.NET MVC Core Identity所做的那样),值为" Google"。每个声明都包含一个范围,以便可以识别声明是否具有外部,本地或两者的含义(或根据需要更细粒度)。
关键点是所有声明都明确附加到身份并包含明确的范围。这些声明当然可以用于授权 - 而ASP.NET MVC通过Authorize属性提供对它的支持,但这不是声明的唯一或必然的主要目的。它当然不能与Roles区分开来,Roles可以完全相同的方式用于本地范围的授权。
因此,只要这些角色和声明属于本地作用域,就可以选择使用角色或声明或两者来进行授权,并且可能没有找到任何固有的优势或劣势。但是,如果授权依赖于外部身份声明,那么角色将是不充分的。您必须接受外部声明并将其转换为本地范围的角色。这并没有什么不妥,但它引入了一层间接并丢弃了上下文。
答案 3 :(得分:23)
我现在已经实现了很多次安全模型,并且还不得不围绕这些概念进行思考。做了很多次,这就是我对这些概念的理解。
什么是角色
角色=用户和权限的联盟。
一方面,角色是权限的集合。我喜欢称它为权限配置文件。定义角色时,基本上是在该角色中添加了一堆权限,因此从某种意义上说,角色是权限配置文件。
另一方面,角色也是用户的集合。如果将Bob和Alice添加到角色“经理”中,则“经理”现在包含两个用户的集合,有点像一个组。
事实是,角色既是用户的集合又是权限的集合。在视觉上,可以将其视为维恩图。
什么是组
组=用户集合
“组”严格来说是用户的集合。组和角色之间的区别在于,角色也具有权限的集合,而组仅具有用户的集合。
什么是权限
权限=主题可以做什么
什么是权限集
权限集=权限集合
在功能强大的RBAC系统中,权限也可以像“用户”一样进行分组。组是仅用户的集合,而权限集仅是权限的集合。这使管理员可以一次将整个权限集合添加到角色。
用户,组,角色和权限如何组合在一起
在功能强大的RBAC系统中,可以将用户单独添加到角色中以创建角色中的用户集合,也可以将组添加到角色中以一次将用户集合添加到角色中。无论哪种方式,角色都可以通过单独添加角色或通过将组添加到角色或通过将用户和组的混合添加到角色来获取其用户集合。可以以相同的方式考虑权限。
可以将权限分别添加到角色,以在角色内部创建权限集合,也可以将权限集添加到角色。最后,可以将权限和权限集混合添加到角色。无论哪种方式,角色都可以通过单独添加权限或通过向角色添加权限集来获取其权限集合。
角色的整个目的是使用户嫁给权限。因此,角色是用户和权限的联合。
什么是索赔
要求=主题“是”
索赔不是许可。如前面的答案所指出的,主张是主体“是”而不是主体“可以做什么”。
声明不会取代角色或权限,它们是可以用来做出授权决策的其他信息。
何时使用声明
我发现,在无法将用户添加到角色或该决策不是基于用户与许可的关联时,需要做出授权决策时,声明非常有用。 Facebook用户的示例导致了这种情况。 Facebook用户可能不是添加到“角色”中的人……他们只是通过Facebook进行身份验证的一些访问者。尽管它不完全适合RBAC,但它是做出授权决定的一条信息。
@CodingSoft在上一个答案中使用了夜总会的隐喻,我想对此进行扩展。在该答案中,以“驾驶执照”为例,其中包含一组索赔,其中“出生日期”代表其中一项索赔,“出生日期”索赔的值用于对照授权规则进行测试。颁发驾驶执照的政府是赋予索赔真实性的机构。因此,在夜总会的情况下,门旁的保镖会查看该人的驾驶执照,并通过检查该证件是否为假ID(即必须是政府颁发的有效ID)来确保它是由受信任的机构签发的,然后查看出生日期(驾驶执照上的许多索偿要求之一),然后使用该值确定此人的年龄是否足以进入俱乐部。如果是这样,那么该人将通过具有有效的声明而不是通过扮演某些角色来通过授权规则。
现在,考虑到这一点,我现在想进一步扩展。假设夜总会所在的建筑物包含办公室,房间,厨房,其他楼层,电梯,地下室等,只有夜总会员工可以进入。此外,某些员工可能有权访问其他员工可能无法访问的某些地方。例如,经理可能有权访问其他员工无法访问的办公楼层。在这种情况下,有两个角色。经理和员工。
尽管如上所述,访问者进入公共夜总会区的权利受到单个索赔的授权,但员工需要通过“角色”来访问其他非公共受限房间。对于他们来说,驾驶执照还不够。他们需要的是员工徽章,他们可以扫描进入大门。某个地方有一个RBAC系统,该系统授予“经理角色”中的徽章访问顶层,并授予“员工角色”中的徽章访问其他房间。
如果出于某种原因需要通过角色添加/删除某些房间,则可以使用RBAC进行此操作,但这并不适合索赔。
软件权限
将角色编码到应用程序中是个坏主意。这会将角色的用途硬编码到应用程序中。该应用程序应该具有的只是功能类似于功能标志的权限。在通过配置使功能标记可访问的情况下,可以通过用户安全上下文来访问权限,该用户安全上下文是从放置用户的所有角色中收集的权限的DISTINCT权限集合派生的。这就是我所说的“有效权限”。该应用程序应该仅显示功能/动作可能的权限的菜单。 RBAC系统应完成通过角色将这些权限与用户结合的工作。这样,就无需对角色进行硬编码,并且只有更改权限或添加新权限后,权限才会发生变化。将权限添加到软件后,就永远不能更改它。仅应在必要时将其删除(即,在新版本中不再使用某项功能时),并且只能添加新功能。
最后的笔记。
格兰特vs拒绝
强大的RBAC系统甚至CBAC系统都应在Grants和Denials之间进行区分。
向角色添加权限应随GRANT或DENY一起提供。选中权限后,应将所有已授予的权限添加到“有效权限的用户”列表中。然后,在完成所有这些操作之后,DENIED Permissions列表应使系统从Effective Permissions列表中删除这些Permissions。
这使管理员可以“调整”主题的最终许可。最好也可以将权限直接添加到用户。这样,您可以将用户添加到管理员角色,这样他们就可以访问所有内容,但是由于用户是男性,因此您可能想拒绝访问女士洗手间。因此,您可以将男性用户添加到管理员角色,并为带有DENY的User对象添加权限,这样它就不会占用该女士房间的访问权限。
实际上,这将是一个不错的选择。如果用户的索赔为“ gender = male”,则处于“管理者”角色可以访问所有房间,但女士洗手间也要求Claim性别=女,而男士洗手间要求Claim性别= male。通过这种方式,不必为男性用户配置DENY权限,因为Claim强制使用单个授权规则为每个人处理该权限。但是,可以通过任何一种方式完成。
要点是,通过拒绝权限,可以实现异常,因此可以更轻松地管理角色。
下面是我很久以前制作的一个图表,其中显示了RBAC模型。我没有索赔的图形,但您可以想象它们只是附加到用户的属性,无论它们位于何处。此外,该图未显示“组”(我需要在某个时候对其进行更新)。
我希望这会有所帮助。
This is a Diagram of the RBAC Described Above
2019年4月7日更新 基于@Brent的反馈(谢谢)...删除了对先前答案的不必要引用,并解释了@CodingSoft提供的“夜总会”隐喻的原始基础,以使此答案易于理解,而不必阅读其他答案。 / p>
答案 4 :(得分:7)
更广泛地说,您应该考虑基于属性的访问控制(ABAC)。 RBAC和ABAC都是由美国国家标准与技术研究院NIST定义的概念。另一方面,CBAC是微软推出的模型,与ABAC非常相似。
在这里阅读更多内容:
答案 5 :(得分:5)
RBAC和CBAC之间的基础是:
RBAC :必须将用户分配给有权执行操作的角色。
CBAC :用户必须拥有具有正确价值的声明,并按照应用程序的预期进行授权。基于声明的访问控制优雅,易于编写。
除了由您的应用程序(依赖方)信任的发布授权服务(安全服务令牌STS)向应用程序发出的声明
答案 6 :(得分:5)
角色只是一种声明。像这样,可以有许多其他声明类型,例如用户名是声明类型之一
答案 7 :(得分:4)
在决定哪种方法最佳之前,首先要分析需要身份验证的内容非常重要。从下面的Microsoft文档中,它说“索赔不是主题可以做的。例如,您可能拥有驾驶执照,由当地驾驶执照机构颁发。您的驾驶执照上有您的出生日期。在这种情况下索赔名称是DateOfBirth,索赔价值将是您的出生日期,例如1970年6月8日,发行人将是驾驶执照机构。基于索赔的授权,最简单的,检查索赔的价值并允许访问基于该值的资源。例如,如果您想要访问夜总会,授权过程可能是:6“ 在给予您访问权限之前,门保安员会评估您的出生日期索赔的价值以及他们是否信任发卡机构(驾驶执照机构)。
从这个例子中我们可以看到,使用基于声明的授权访问附近的俱乐部与在夜总会工作的员工所需的授权类型不同,在这种情况下,夜间的工作人员俱乐部将要求夜总会访客不需要基于角色的授权,因为夜总会访客在夜总会都有共同目的,因此在这种情况下,基于声明的授权适合夜总会访客。
基于角色的授权 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles 二〇一六年十月十四日 创建身份时,它可能属于一个或多个角色。例如,Tracy可能属于管理员和用户角色,而Scott可能只属于User角色。如何创建和管理这些角色取决于授权过程的后备存储。角色通过ClaimsPrincipal类上的IsInRole方法暴露给开发人员。
基于声明的授权 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims 二〇一六年十月十四日 当创建身份时,可以为其分配由受信任方发布的一个或多个声明。声明是名称值对,表示主题是什么,而不是主题可以做什么。例如,您可能拥有由当地驾驶执照颁发机构颁发的驾驶执照。您的驾驶执照上有您的出生日期。在这种情况下,索赔名称将是DateOfBirth,索赔值将是您的出生日期,例如1970年6月8日,发行人将是驾驶执照当局。基于声明的授权最简单地检查声明的值,并允许基于该值访问资源。例如,如果您想要访问夜总会,授权过程可能是:
门保安员会在授予您访问权限之前评估您的出生日期索赔的价值以及他们是否信任发卡机构(驾驶执照机构)。
标识可以包含多个具有多个值的声明,并且可以包含多个相同类型的声明。
答案 8 :(得分:2)
也可以以索赔方式管理角色。
创建反映操作角色的角色,而不是创建反映业务角色的授权角色,例如CreateCustomer,EditCustomer,DeleteCustomer。根据需要注释方法。
将个人映射到一组操作角色并不是一件简单的事情,尤其是当角色列表变大时。因此,您需要以较低的粒度级别(例如,销售,市场营销)管理业务角色,并将业务角色映射到所需的操作角色。即,将用户添加到业务角色,并将其映射到现有授权表中的必需(操作)角色。
您甚至可以覆盖业务角色并直接将人员添加到操作角色。
由于您构建的基础已经有效,因此您不会撤消现有的授权过程。您只需要几个表来实现此方法
答案 9 :(得分:1)
我认为这个问题可以从数据库的角度来回答。 如果您注意到这种植入所涉及的表格,您将找到以下内容
可以在用户/应用程序生命周期的某个时刻调整此表的使用,以满足特定需求。
考虑采购经理的早期阶段" (PM),我们可以有三种方法
应用程序使用一行填充AspNetUserRoles以授予' PM'有权购买。要发出任何金额的采购订单,用户只需要" PM"作用。
应用程序使用一行填充AspNetUserRoles以授予' PM'购买的权利,并填写AspNetUserClaims声称TYPE'采购金额'类型和"< 1000"设置金额限制的值。要发出采购订单,用户需要有PM'订单金额低于索赔类型的索赔价值'采购金额'
应用程序填充AspNetUserClaims,声明为TYPE'采购金额'类型和"< 1000"值。任何用户都可以发出采购订单,因为金额低于索赔类型的索赔价值'采购金额'对于这个用户。
正如可以注意到的那样,基于角色的粗略权限是粗略的,从系统管理的角度来看会简化应用程序用户的生命。但是从业务需求的角度来看,它会限制用户的能力。 另一方面,基于声明的是需要分配给每个用户的非常好的权限。声明基础将推动业务的极限,但会使系统管理变得非常复杂。
答案 10 :(得分:1)
如果您想要一个真实的例子;
您拥有学校系统,老师可以登录并查看他们的学生。这些老师担任“ 老师”角色。但是我们不希望所有的老师都能看到所有的学生,因此我们需要根据他们的主张来区分同一级别的人。
虽然这三位老师都在 Teacher 角色下,但他们只能看到具有相应索赔的学生。
还有一个叫迈克的校长:
如果我们需要区分管理员级别的人员,可以为他们分配相关的主张。