ThinkPHP中關於RBAC使用詳解
RBAC是什麼,能解決什麼難題?
RBAC是Role-Based Access Control的首字母,譯成中文即基於角色的許可權訪問控制,說白了也就是使用者通過角色與許可權進行關聯[其架構靈感來源於作業系統的GBAC(GROUP-Based Access Control)的許可權管理控制]。簡單的來說,一個使用者可以擁有若干角色,每一個角色擁有若干許可權。這樣,就構造成“使用者-角色-許可權”的授權模型。在這種模型中,使用者與角色之間,角色與許可權之間,一般者是多對多的關係。其對應關係如下:
在許多的實際應用中,系統不只是需要使用者完成簡單的註冊,還需要對不同級別的使用者對不同資源的訪問具有不同的操作許可權。且在企業開發中,許可權管理系統也成了重複開發效率最高的一個模組之一。而在多套系統中,對應的許可權管理只能滿足自身系統的管理需要,無論是在資料庫設計、許可權訪問和許可權管理機制方式上都可能不同,這種不致性也就存在如下的憋端:
- 維護多套系統,重複造輪子,時間沒用在刀刃上
- 使用者管理、組織機制等資料重複維護,資料的完整性、一致性很難得到保障
- 許可權系統設計不同,概念理解不同,及相應技術差異,系統之間整合存在問題,單點登入難度大,也複雜的企業系統帶來困難
RBAC是基於不斷實踐之後,提出的一個比較成熟的訪問控制方案。實踐表明,採用基於RBAC模型的許可權管理系統具有以下優勢:由於角色、許可權之間的變化比角色、使用者關係之間的變化相對要慢得多,減小了授權管理的複雜性,降低管理開銷;而且能夠靈活地支援應用系統的安全策略,並對應用系統的變化有很大的伸縮性;在操作上,許可權分配直觀、容易理解,便於使用;分級許可權適合分層的使用者級形式;重用性強。
ThinkPHP中RBAC實現體系
ThinkPHP中RBAC基於Java的Spring的Acegi安全系統作為參考原型,並做了相應的簡化處理,以適應當前的ThinkPHP結構,提供一個多層、可定製的安全體系來為應用開發提供安全控制。安全體系中主要有以下幾部分:
- 安全攔截器
- 認證管理器
- 決策訪問管理器
- 執行身份管理器
安全攔截器
安全攔截器就好比一道道門,在系統的安全防護系統中可能存在很多不同的安全控制環節,一旦某個環節你未通過安全體系認證,那麼安全攔截器就會實施攔截。
認證管理器
防護體系的第一道門就是認證管理器,認證管理器負責決定你是誰,一般它通過驗證你的主體(通常是一個使用者名稱)和你的憑證(通常是一個密碼),或者更多的資料來做到。更簡單的說,認證管理器驗證你的身份是否在安全防護體系授權範圍之內。
訪問決策管理
雖然通過了認證管理器的身份驗證,但是並不代表你可以在系統裡面肆意妄為,因為你還需要通過訪問決策管理這道門。訪問決策管理器對使用者進行授權,通過考慮你的身份認證資訊和與受保護資源關聯的安全屬性決定是是否可以進入系統的某個模組,和進行某項操作。例如,安全規則規定只有主管才允許訪問某個模組,而你並沒有被授予主管許可權,那麼安全攔截器會攔截你的訪問操作。
決策訪問管理器不能單獨執行,必須首先依賴認證管理器進行身份確認,因此,在載入訪問決策過濾器的時候已經包含了認證管理器和決策訪問管理器。
為了滿足應用的不同需要,ThinkPHP 在進行訪問決策管理的時候採用兩種模式:登入模式和即時模式。登入模式,系統在使用者登入的時候讀取改使用者所具備的授權資訊到 Session,下次不再重新獲取授權資訊。也就是說即使管理員對該使用者進行了許可權修改,使用者也必須在下次登入後才能生效。即時模式就是為了解決上面的問題,在每次訪問系統的模組或者操作時候,進行即使驗證該使用者是否具有該模組和操作的授權,從更高程度上保障了系統的安全。
執行身份管理器
執行身份管理器的用處在大多數應用系統中是有限的,例如某個操作和模組需要多個身份的安全需求,執行身份管理器可以用另一個身份替換你目前的身份,從而允許你訪問應用系統內部更深處的受保護物件。這一層安全體系目前的 RBAC 中尚未實現。
ThinkPHP中RBAC認證流程
對應上面的安全體系,ThinkPHP 的 RBAC 認證的過程大致如下:
- 判斷當前模組的當前操作是否需要認證
- 如果需要認證並且尚未登入,跳到認證閘道器,如果已經登入 執行5
- 通過委託認證進行使用者身份認證
- 獲取使用者的決策訪問列表
- 判斷當前使用者是否具有訪問許可權
許可權管理的具體實現過程
RBAC相關的資料庫介紹
在ThinkPHP完整包,包含了RBAC處理類RBAC.class.php檔案,
位於Extend/Library/ORG/Util
。開啟該檔案,其中就包含了使用RBAC必備的4張表,SQL語句如下(複製後請替換表字首):
- CREATE TABLE IF NOT EXISTS `ly_access`(
- `role_id` smallint(6)unsigned NOT NULL,
- `node_id` smallint(6)unsigned NOT NULL,
- `level` tinyint(1) NOT NULL,
- `module` varchar(50) DEFAULT NULL,
- KEY `groupId`(`role_id`),
- KEY `nodeId`(`node_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
- CREATE TABLE IF NOT EXISTS `ly_node`(
- `id` smallint(6)unsigned NOT NULL AUTO_INCREMENT,
- `name` varchar(20) NOT NULL,
- `title` varchar(50) DEFAULT NULL,
- `status` tinyint(1) DEFAULT '0',
- `remark` varchar(255) DEFAULT NULL,
- `sort` smallint(6)unsigned DEFAULT NULL,
- `pid` smallint(6)unsigned NOT NULL,
- `level` tinyint(1)unsigned NOT NULL,
- PRIMARY KEY (`id`),
- KEY `level`(`level`),
- KEY `pid`(`pid`),
- KEY `status`(`status`),
- KEY `name`(`name`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
- CREATE TABLE IF NOT EXISTS `ly_role`(
- `id` smallint(6)unsigned NOT NULL AUTO_INCREMENT,
- `name` varchar(20) NOT NULL,
- `pid` smallint(6) DEFAULT NULL,
- `status` tinyint(1)unsigned DEFAULT NULL,
- `remark` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `pid`(`pid`),
- KEY `status`(`status`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
- CREATE TABLE IF NOT EXISTS `ly_role_user`(
- `role_id` mediumint(9)unsigned DEFAULT NULL,
- `user_id`char(32) DEFAULT NULL,
- KEY `group_id`(`role_id`),
- KEY `user_id`(`user_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
下面對RBAC相關的資料庫表及欄位作一下介紹:
表名 | 欄位名 | 欄位型別 | 作用 |
---|---|---|---|
ly_user | id | INT | 使用者ID(唯一識別號) |
username | VARCHAR(16) | 使用者名稱 | |
password | VARCHAR(32) | 密碼 | |
VARCHAR(100) | 使用者郵箱 | ||
create_time | TIMESTAMP | 建立時間(時間戳) | |
logintime | TIMESTAMP | 最近一次登入時間(時間戳) | |
loginip | VARCHAR(15) | 最近登入的IP地址 | |
status | TINYINT(1) | 啟用狀態:0:表示禁用;1:表示啟用 | |
remark | VARCHAR(255) | 備註資訊 | |
ly_role | id | INT | 角色ID |
name | VARCHAR(20) | 角色名稱 | |
pid | SMALLINT(6) | 父角色對應ID | |
status | TINYINT(1) | 啟用狀態(同上) | |
remark | VARCHAR(255) | 備註資訊 | |
ly_node | id | SMALLINT(6) | 節點ID |
name | VARCHAR(20) | 節點名稱(英文名,對應應用控制器、應用、方法名) | |
title | VARCHAR(50) | 節點中文名(方便看懂) | |
status | TINYINT(1) | 啟用狀態(同上) | |
remark | VARCHAR(255) | 備註資訊 | |
sort | SMALLINT(6) | 排序值(預設值為50) | |
pid | SMALLINT(6) | 父節點ID(如:方法pid對應相應的控制器) | |
level | TINYINT(1) | 節點型別:1:表示應用(模組);2:表示控制器;3:表示方法 | |
ly_role_user | user_id | INT | 使用者ID |
role_id | SMALLINT(6) | 角色ID | |
ly_access | role_id | SMALLINT(6) | 角色ID |
node_id | SMALLINT(6) | 節點ID | |
level | |||
module |
以下是資料庫表各欄位的關聯關係:
實現RBAC管理的前導性工作
基於ThinkPHP實現RBAC的許可權管理系統中,首先要做一些前導性的工作(系統資料庫設計TP已經為我們完成了),主要分以下幾個方面:
- 使用者(增、刪、改、查)
- 角色(增、刪、改、查)
- 節點(增、刪、改、查)
- 配置許可權(更新許可權)
具體實現的程式碼如下(相關解釋均在註釋之中):
複製
- <?php
- /**
- * Created by PhpStorm.
- * User: LiuYang
- * Date: 14-9-6
- * Time: 下午9:54
- * Description: 基於ThinkPHP實現的許可權管理系統
- */
- classRbacActionextendsCommonAction{
- //初始化操作
- function _initialize