Q0.有哪些概念須要知道?
一些概念的具體定義以下php
- 用戶(user): 和計算機系統交互的人(在許多設計方案中,單個用戶可能擁有多個登陸標識(ID),這些標識可能同時處於活躍狀態,但身份驗證機制可使多個標識匹配到某個具體的人,即用戶對於計算機系統來講具備惟一性)
- 主體(subject): 一個表明用戶行爲的計算機進程(能夠當作是用戶的agent)
- 客體(object): 計算機系統中任意可訪問的資源
- 操做(operation): 由客體觸發的活動進程
- 權限(permission): 系統中受權能夠執行的動做,即客體和操做的組合
- 角色: 不一樣權限或角色(職責)的集合
- 會話(session) : 用戶和系統交互的實例
Q1.什麼是RBAC?
- 請自行參考百度百科和維基百科
- 核心概念:用戶經過指派角色而獲取相應的權限,而非直接把權限賦予用戶
Q2.RBAC爲何經過角色來爲用戶分配權限,而不直接把權限賦予用戶?
一般用戶和權限的關係變動頻繁,而角色和權限的關係則相對穩定。例如,系統中某個用戶辭職了,只須要將系統中該用戶的角色受權撤銷便可。git
Q3.RBAC0,RBAC1,RBAC2,RBAC3有什麼聯繫?
RBAC0總結:
github
- 元素: 用戶,角色,權限,組成權限的操做,操做對應的客體
- 映射: 用戶-角色,角色-權限(角色與角色,角色與權限之間沒有多層繼承)
- 權限: 綁定在在計算機操做和資源客體上的抽象概念(操做 + 客體)
- RBAC基礎模型的動態組件包括: 角色激活和主體訪問
- 主體: 可以訪問處於控制下的角色、操做和客體的活動實體(主體表明用戶完成其全部請求,主體到用戶應是單一映射,而用戶到主體則不必定),這個概念主要出如今動態模型中
RBAC1總結:
安全
- 基於rbac0,與rbac0的區別是角色之間能夠多層繼承
- 使用多層角色的緣由:單一角色一般出現功能重疊的現象(屬於不一樣角色的用戶都會被授予一些通常性權限)
- 鏈接器角色:一般不直接賦予用戶;能夠包含任意的權限集,做爲抽象功能,抽象職責,抽象任務或抽象活動(便於重用);一般若是在角色中有80%或更多的權限重疊,那麼就能夠選擇建立一個鏈接器角色;
RBAC2總結:
yii2
- 基於rbac0,與rbac0的區別是增長約束概念(主要是職責分離約束)
- 職責分離(SoD): 關鍵操做必須由兩個或更多的人來完成,這樣任何一我的都不可能單獨的破壞安全系統(因此在rbac中知足職責分離約束即有效角色A和有效角色B對應的用戶集合不能有交集)
- 職責分離方法: 靜態和動態方法
- 靜態職責分離模型:在爲用戶指派角色時,就爲角色施加約束(例如,若是爲某用戶授予角色A,就不能再爲其授予角色B)
- 動態職責分離模型:用戶以活動狀態使用系統時其約束纔會發揮做用(例如,它能夠同時賦予某用戶角色A和角色B,但不容許在一個會話中同時充當兩個角色)
Q4.在編碼實踐中RBAC模塊可能包含什麼?
- 用戶管理:用戶的增刪改查
- 角色管理:角色的增刪改查
- 權限管理:權限的增刪改查
- 日誌管理:日誌的增刪改查
- 受權與撤銷受權操做
- 資源管理:資源的增刪改查(注意:這裏的資源指的是那些須要被rbac模塊進行權限管理的資源)
- 權限判斷操做:提供用於判斷權限的接口(常見形式如:checkAccess(user,role,params))
- 會話管理:即對用戶在當前交互中的活動角色進行管理
Q5.身份鑑別與rbac中權限授予的區別與聯繫?
- 權限授予和身份鑑別是訪問控制的基礎
- 正確的權限授予事實上依賴於身份鑑別
- 身份鑑別是肯定「你是誰「的過程;權限授予則是肯定」你能幹什麼「的過程(即權限授予機制對用戶是否能夠訪問系統資源作出」是「或」否「的決定)
Q6.在RBAC1中如何設計權限繼承結構?
如下僅爲我的經驗session
- 分析系統,列出一些可能存在的角色
- 分析系統,列出全部須要被管理的資源
- 對每種資源列出全部須要被管理的操做
- 根據每種資源的每種操做,組合出全部的基本(操做,資源)(只分析須要進行權限管理的),造成"最底層permission"
- 對全部當前存在的permission構成的集合進行逐層劃分(按照最小權限原則,並聯系可能存在的角色)
- 根據上一步的劃分,在每個分界處提取出角色(其中可能包含鏈接器角色)
- 整理以上的工做,獲得基本權限繼承結構
- 對基本權限繼承結構中的元素進行分析,肯定是否須要附加rule(rule能夠用於確保是在知足一些前置條件的狀況下進行權限斷定,rule不必定非要附加在permission或role上,也能夠附加於assignment上,看實際編碼時的考慮)
- 將帶有rule的"permission"做爲其"最底層permission"的上層權限,最後若是"最底層permission"沒有上層角色,則能夠考慮從結構中刪除
- 整理並回顧,優化每一個元素的命名
- 若是在第7步中不選擇在permission或role上附加rule,則須要考慮如何在assignment上附加rule
Q7.在實際項目中會常常遇到角色是基於某種資源的狀況,該如何處理?
問題的具體描述:yii
- 在某一系統中,資源(客體)A須要進行權限管理。(A指的是一類資源,假設其中包括具體的該類資源a,b,c...)
- 存在用戶u,u能夠訪問(access)A類資源中的a和b
- 用戶u對於資源a被賦予角色r1,u對於資源b被賦予角色r2
須要如何實現rbac使得其知足以上需求?優化
Answer:this
- 一般須要在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;
}