Q0.有哪些概念需要知道?
一些概念的具体定义如下
- 用户(user): 和计算机系统交互的人(在许多设计方案中,单个用户可能拥有多个登录标识(ID),这些标识可能同时处于活跃状态,但身份验证机制可以使多个标识匹配到某个具体的人,即用户对于计算机系统来说具有唯一性)
- 主体(subject): 一个代表用户行为的计算机进程(可以看成是用户的agent)
- 客体(object): 计算机系统中任意可访问的资源
- 操作(operation): 由客体触发的活动进程
- 权限(permission): 系统中授权可以执行的动作,即客体和操作的组合
- 角色: 不同权限或角色(职责)的集合
- 会话(session) : 用户和系统交互的实例
Q1.什么是RBAC?
- 请自行参考百度百科和维基百科
- 核心概念:用户通过指派角色而获取相应的权限,而非直接把权限赋予用户
Q2.RBAC为什么通过角色来为用户分配权限,而不直接把权限赋予用户?
通常用户和权限的关系变更频繁,而角色和权限的关系则相对稳定。例如,系统中某个用户辞职了,只需要将系统中该用户的角色授权撤销即可。
Q3.RBAC0,RBAC1,RBAC2,RBAC3有什么联系?
RBAC0总结:
- 元素: 用户,角色,权限,组成权限的操作,操作对应的客体
- 映射: 用户-角色,角色-权限(角色与角色,角色与权限之间没有多层继承)
- 权限: 绑定在在计算机操作和资源客体上的抽象概念(操作 + 客体)
- RBAC基础模型的动态组件包括: 角色激活和主体访问
- 主体: 能够访问处于控制下的角色、操作和客体的活动实体(主体代表用户完成其所有请求,主体到用户应是单一映射,而用户到主体则不一定),这个概念主要出现在动态模型中
RBAC1总结:
- 基于rbac0,与rbac0的区别是角色之间可以多层继承
- 使用多层角色的原因:单一角色通常出现功能重叠的现象(属于不同角色的用户都会被授予一些一般性权限)
- 连接器角色:通常不直接赋予用户;可以包含任意的权限集,作为抽象功能,抽象职责,抽象任务或抽象活动(便于重用);通常如果在角色中有80%或更多的权限重叠,那么就可以选择创建一个连接器角色;
RBAC2总结:
- 基于rbac0,与rbac0的区别是增加约束概念(主要是职责分离约束)
- 职责分离(SoD): 关键操作必须由两个或更多的人来完成,这样任何一个人都不可能单独的破坏安全系统(所以在rbac中满足职责分离约束即有效角色A和有效角色B对应的用户集合不能有交集)
- 职责分离方法: 静态和动态方法
- 静态职责分离模型:在为用户指派角色时,就为角色施加约束(例如,如果为某用户授予角色A,就不能再为其授予角色B)
- 动态职责分离模型:用户以活动状态使用系统时其约束才会发挥作用(例如,它可以同时赋予某用户角色A和角色B,但不允许在一个会话中同时充当两个角色)
Q4.在编码实践中RBAC模块可能包含什么?
- 用户管理:用户的增删改查
- 角色管理:角色的增删改查
- 权限管理:权限的增删改查
- 日志管理:日志的增删改查
- 授权与撤销授权操作
- 资源管理:资源的增删改查(注意:这里的资源指的是那些需要被rbac模块进行权限管理的资源)
- 权限判断操作:提供用于判断权限的接口(常见形式如:checkAccess(user,role,params))
- 会话管理:即对用户在当前交互中的活动角色进行管理
Q5.身份鉴别与rbac中权限授予的区别与联系?
- 权限授予和身份鉴别是访问控制的基础
- 正确的权限授予事实上依赖于身份鉴别
- 身份鉴别是确定“你是谁“的过程;权限授予则是确定”你能干什么“的过程(即权限授予机制对用户是否可以访问系统资源做出”是“或”否“的决定)
Q6.在RBAC1中如何设计权限继承结构?
以下仅为个人经验
- 分析系统,列出一些可能存在的角色
- 分析系统,列出所有需要被管理的资源
- 对每种资源列出所有需要被管理的操作
- 根据每种资源的每种操作,组合出所有的基本(操作,资源)(只分析需要进行权限管理的),形成"最底层permission"
- 对所有当前存在的permission构成的集合进行逐层划分(按照最小权限原则,并联系可能存在的角色)
- 根据上一步的划分,在每一个分界处提取出角色(其中可能包含连接器角色)
- 整理以上的工作,得到基本权限继承结构
- 对基本权限继承结构中的元素进行分析,确定是否需要附加rule(rule可以用于确保是在满足一些前置条件的情况下进行权限判定,rule不一定非要附加在permission或role上,也可以附加于assignment上,看实际编码时的考虑)
- 将带有rule的"permission"作为其"最底层permission"的上层权限,最后如果"最底层permission"没有上层角色,则可以考虑从结构中删除
- 整理并回顾,优化每个元素的命名
- 如果在第7步中不选择在permission或role上附加rule,则需要考虑如何在assignment上附加rule
Q7.在实际项目中会经常遇到角色是基于某种资源的情况,该如何处理?
问题的具体描述:
- 在某一系统中,资源(客体)A需要进行权限管理。(A指的是一类资源,假设其中包括具体的该类资源a,b,c...)
- 存在用户u,u可以访问(access)A类资源中的a和b
- 用户u对于资源a被赋予角色r1,u对于资源b被赋予角色r2
需要如何实现rbac使得其满足以上需求?
Answer:
- 通常需要在rbac添加一个新的基本元素rule,rule的作用在于:当进行权限判定时,限定前置条件。
- rule可以附加在permission,role或assignment(即某个用户赋予某种角色:(user,role))中,在判定权限过程中,需要执行rule
- 对应于上面的问题,可以添加一张表T,T中的每条记录包含(user,resourceA,role),执行rule的目的是判断(u,a,r1)或(u,b,r2)存在于表T中
- 个人偏向于在assignment中绑定rule,这样可以使权限继承结构更为清晰
Q8.在实现rbac时,进行权限判定的具体逻辑是怎样的?
通常在实现的时候会用到递归,下面以YII2中提供的代码为例(源码在yii2中的位置为vendor\yiisoft\yii2\rbac\DbManager.php,这里的代码删减了一些无关的内容)
public function checkAccess($userId, $permissionName, $params = [])
{
$assignments = $this->getAssignments($userId);//先查找当前用户的已经授予的所有角色
if ($this->hasNoAssignments($assignments)) {
return false;//如果没有任何授权的话,当然是判定失败
}
//递归
return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments);
}
protected function checkAccessRecursive($user, $itemName, $params, $assignments)
{
if (($item = $this->getItem($itemName)) === null) {
return false;//如果所要判定的permission或role根本不存在,自然判定失败
}
//需要判定的item存在,先执行当前Item的rule,rule可以用于执行一些业务逻辑
if (!$this->executeRule($user, $item, $params)) {
return false;
}
//如果当前需要判定的role确实授予了该用户,那么就可以返回true,结束递归
if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) {
return true;
}
//获取当前Item的上一层item,递归判定
$query = new Query;
$parents = $query->select(['parent'])
->from($this->itemChildTable)
->where(['child' => $itemName])
->column($this->db);
foreach ($parents as $parent) {
if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) {
return true;
}
}
return false;
}
- 在上面的代码中可以看到,当中使用了rule,在yii2中可以在permission或role中绑定相应的rule(但在assignment中无法绑定rule),引入rule可以解决Q7中的问题
- 为了实现在assignment中绑定rule,以下是经过修改后的代码(除了checkAccessRecursive方法需要修改外,还有其他的相关方法需要修改,但此处就不列出了,具体可以查看github项目:https://github.com/Darkgel/tr...)
protected function checkAccessRecursive($user, $itemName, $params, $assignments)
{
if (($item = $this->getItem($itemName)) === null) {
return false;
}
if (!$this->executeRule($user, $item, $params)) {
return false;
}
if(in_array($itemName, $this->defaultRoles)){
return true;
}
//这里添加了对assignment中的rule进行判断
if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName];
if($this->executeRule($user, $assignment, $params)){
return true;
}
}
$query = new Query;
$parents = $query->select(['parent'])
->from($this->itemChildTable)
->where(['child' => $itemName])
->column($this->db);
foreach ($parents as $parent) {
if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) {
return true;
}
}
return false;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。