26、生鮮電商平臺-RBAC系統許可權的設計與架構
說明:根據上面的需求描述以及對需求的分析,我們得知通常的一箇中小型系統對於許可權系統所需實現的功能以及非功能性的需求,在下面我們將根據需求從技術角度上分析實現的策略以及基於目前兩種比較流行的許可權設計思想來討論關於許可權系統的實現。
1.1. 技術策略
l 身份認證
在B/S的系統中,為識別使用者身份,通常使用的技術策略為將使用者的身份記錄在Session中,也就是當用戶登入時即獲取使用者的身份資訊,並將其記錄到Session裡,當需要進行身份認證的時候通過從Session中獲取使用者的身份資訊來實現使用者的身份認證。
l 資源許可權校驗
資源許可權校驗取決於系統的授權模型,這塊將在之後進行詳細的闡述。
l 資料許可權校驗
資料許可權校驗取決於系統的授權模型,這塊將在之後進行詳細的闡述。
l 授權模型
授權模型作為許可權系統的核心,從本質上決定了許可權系統的易用性,這個易用性包括許可權的授予和許可權的校驗,並同時也決定了許可權的繼承,許可權的排斥和包含等方面的實現。
在經歷了這麼多年的發展,授權模型在目前中小型應用系統接受的比較多的主要有RBAC模型和ACL模型,將在之後展開專門的篇幅進行講解。
l 許可權校驗的體現
許可權校驗的體現在中小型系統中體現出來的通常只是對於系統選單、按鈕顯示的控制和對於擁有許可權的資料的訪問上。
它們共同依賴於資源許可權校驗和資料許可權校驗,對於系統選單、按鈕的顯示上的控制在B/S中通常採用的技術策略為在生成選單、按鈕的Html時做許可權級的判斷,當操作主體不具備許可權時則不生成該選單、按鈕的Html,從技術角度分析為方便使用者,避免使用者呼叫許可權校驗介面,通常的做法為提供選單、按鈕的標籤,通過此標籤生成的選單和按鈕即為經過許可權過濾的。
l 高效能
為提高許可權系統在授權以及校驗許可權時的效能,通常的做法為採用快取技術以及加強許可權系統的管理建設,加強許可權系統的管理建設有助於建立一個最為適合需求的許可權結構,同時做到了簡化系統許可權授予。
l 安全性
安全性方面來講在B/S系統中通常有兩個方面需要控制:
n 通過非法途徑訪問系統檔案
在Java的Web應用中通常採用的技術策略為將需要受保護的檔案放入WEB-INF資料夾中,大家都知道在WEB-INF下的檔案除了在伺服器上能直接訪問外,通過普通的URL是無法訪問到的。
其次的做法為做Filter,即對需要受保護的資源做訪問的Filter,如操作者不具備許可權則直接報出錯誤。
n 通過非法途徑訪問系統操作
通常採用的技術策略為對每個直接暴露對外的需要受許可權保護的物件做操作級別的許可權控制,簡單來說在Web系統中通常採用MVC框架來實現,通常Command層是直接對外的,為防止使用者通過URL或其他方式訪問Command,從技術上我們需要考慮對現有系統的儘量少的侵入性,所以通常採用的做法是在Command之上做Before Interceptor或Proxy,在此Interceptor或Proxy中做許可權的校驗,以確認操作者具有相應的許可權。
經過上面的描述,我們已經基本瞭解到滿足許可權系統需求的技術實現策略,從中我們也可以看出許可權系統中最為重要的為授權模型,由於許可權系統的通用性,在業界也是推出了不少的授權模型,在這裡我們已目前比較通用的兩種授權模型來具體講解許可權系統的完整實現。
1.2. 基於RBAC的實現
1.2.1. RBAC介紹
RBAC模型作為目前最為廣泛接受的許可權模型,在此也將對其模型進行簡要的介紹,RBAC模型成功的經典應用案例當屬Unix系統了。
NIST(The National Institute of Standards and Technology,美國國家標準與技術研究院)標準RBAC模型由4個部件模型組成,這4個部件模型分別是基本模型RBAC0(Core RBAC)、角色分級模型RBAC1(Hierarchal RBAC)、角色限制模型RBAC2(Constraint RBAC)和統一模型RBAC3(Combines RBAC)[1]。RBAC0模型如圖1所示。
圖表 1 RBAC 0模型
l RBAC0定義了能構成一個RBAC控制系統的最小的元素集合
在RBAC之中,包含使用者users(USERS)、角色roles(ROLES)、目標objects(OBS)、操作operations(OPS)、許可權permissions(PRMS)五個基本資料元素,許可權被賦予角色,而不是使用者,當一個角色被指定給一個使用者時,此使用者就擁有了該角色所包含的許可權。會話sessions是使用者與啟用的角色集合之間的對映。RBAC0與傳統訪問控制的差別在於增加一層間接性帶來了靈活性,RBAC1、RBAC2、RBAC3都是先後在RBAC0上的擴充套件。
l RBAC1引入角色間的繼承關係
角色間的繼承關係可分為一般繼承關係和受限繼承關係。一般繼承關係僅要求角色繼承關係是一個絕對偏序關係,允許角色間的多繼承。而受限繼承關係則進一步要求角色繼承關係是一個樹結構。
l RBAC2模型中添加了責任分離關係
RBAC2的約束規定了許可權被賦予角色時,或角色被賦予使用者時,以及當用戶在某一時刻啟用一個角色時所應遵循的強制性規則。責任分離包括靜態責任分離和動態責任分離。約束與使用者-角色-許可權關係一起決定了RBAC2模型中使用者的訪問許可。
l RBAC3包含了RBAC1和RBAC2
既提供了角色間的繼承關係,又提供了責任分離關係。
1.2.2. 實現方案
通過上面章節對RBAC的介紹,從RBAC模型中我們可以看出它已經實現了一個使用起來很方便的授權模型,並同時也就許可權的繼承,許可權的排斥和包含提出瞭解決的模型。
那麼現在的關鍵是我們需要來看看基於RBAC到底是怎麼實現許可權系統的需求的呢?在這裡我們針對在技術策略中未描述的授權模型和許可權校驗部分做實現方案的講解。
l 授權模型
授權模型遵循RBAC進行搭建,即建立如上圖表一的模型。
針對授權模型中的幾個關鍵部分我們進行描述:
n 授權
按照RBAC的模型,在授權時分為配置資源以及資源的操作、授予角色對資源的操作許可權、分配角色給使用者這幾個步驟來完成。
從這幾個步驟我們進行分析:
u 配置資源以及資源的操作
實現這步非常的簡單,直接維護資源以及資源操作兩個物件的持久即可實現。
u 授予角色對資源的操作許可權
實現這步同樣非常的簡單,維護角色與資源的關聯模型即可。
u 分配角色給使用者
實現這步同樣非常的簡單,維護角色與使用者的關聯模型即可。
n 許可權的繼承
許可權的繼承在RBAC的模型中通過增加角色的自關聯來實現,即角色可擁有子角色,子角色繼承父角色的許可權。
按照此模型可以看出在授權時維護許可權的繼承也是非常的簡單,維護角色的自關聯模型即可。
n 許可權的排斥和包含
許可權的排斥和包含這塊我沒有具體看RBAC的規範,通常的做法是通過在資源的操作許可權模型中增加自關聯模型以定義哪些資源的操作許可權是排斥和包含的,在授權時可以看到同樣需要維護的只是資源許可權的自關聯模型。
l 資源許可權校驗
根據上面的授權模型,在做資源許可權校驗的時候需要經過以下步驟:
n 判斷使用者所在的角色是否擁有對資源進行操作的許可權
獲取使用者所擁有的角色,遍歷其角色,以各角色建立Session,並通過類似的role.doPrivilege(Resource,Operation)的方式來判斷該角色是否具備許可權,如具備則直接返回,如不具備則直到遍歷結束。
n 遞規使用者所在角色的父角色判斷是否擁有對資源進行操作的許可權
當遍歷完使用者本身的角色得到使用者不具備對資源進行該操作的許可權時,則開始遞規其所在角色的父角色來判斷是否擁有對資源進行操作的許可權,過程同上,如確定某角色具備,則返回,如不具備直到遞規結束。
l 資料許可權校驗
在RBAC模型中沒有明確定義資料許可權的實現策略,鑑於此首先要講解下基於RBAC模型的資料授權模型的建立,基於RBAC模型,將資料對映為RBAC中的資源,對資料的操作則對映為資源的操作,同樣的是將此資源以及資源的操作構成的許可權授予給角色,將使用者分配給角色完成資料許可權的授權過程。
但根據資料許可權校驗的需求,資料的許可權也是需要繼承的,而且資料許可權的授予物件需要是多種,這樣的話就對上面根據RBAC對映形成的資料許可權的授權模型造成了衝擊,需要重構上面的授權模型來滿足需求。
為實現資料許可權的繼承,需要將RBAC模型中的資源重構為允許自關聯的模型,為實現資料許可權能夠授予給多種物件,需要將本來資源操作許可權授予給角色的模型演變為資料操作許可權授予給角色、組織機構或具體人員,根據RBAC模型,同樣的建立一箇中間物件,此物件和資料操作許可權所授予的物件做1對多的關聯,在經過這樣的重構之後資料許可權的授權模型就形成了,也滿足了資料許可權的繼承和授予給多種物件的需求。
圖表 2 基於RBAC演變的資料許可權模型
上面的圖中少畫了資料的自關聯。
根據上面的資料許可權模型,來看看資料許可權的校驗是怎麼樣去實現呢?
在做資料許可權校驗的時候我們需要實現的為兩種方式,一種是獲取操作主體具有資料操作許可權的全部資料,另外一種為分頁獲取操作主體具有資料操作許可權的資料。
就這兩種方式分別來進行闡述:
n 獲取操作主體具有資料操作許可權的全部資料
從資料庫中獲取所有資料,遍歷取出的資料從資料許可權模型中獲取相應的擁有資料操作許可權的許可權擁有者,如果該資料未配置資料操作許可權的控制,那麼就無需對該資料進行許可權級的判斷,如配置了,則需判斷當前使用者是否在該資料操作許可權所對應的擁有者中,如使用者不在,則需遞規獲取該資料的父資料的操作許可權的擁有者,到使用者擁有許可權或遞規結束時終止。
n 分頁獲取操作主體具有資料操作許可權的資料
分頁的做法和上面差不多,只是在獲取了所有的資料後在記憶體中做分頁返回。
1.2.3. 優缺點分析
從上面的基於RBAC的實現方案中可以看出基於RBAC模型的優點在於:
l 易用和高效的授權方式
使用者在進行授權時只需對角色進行授權,之後將相應的角色分配給使用者即可。
l 簡便和高效的授權模型維護
在技術角度來講,進行授權模型的維護上因為基本只需要維護關聯模型而顯得簡單而高效。
缺點在於:
l 複雜的許可權校驗
在進行許可權校驗時需要不斷的遍歷和遞規,造成了效能的影響。
l 對於資料許可權的不夠支援
沒有明確的資料許可權模型,可以看到在經過重構的資料許可權模型其實已經和RBAC模型有一定的
出入,而且在資料許可權的校驗上實現起來是非常的低效。
最終根據說明,設計如下系統架構圖:
一、設計規則定義
1. 資料庫表明定義規則:t_ 模組名_表名
二、許可權管理系統系統設計
1. 使用者管理(t_sys_userInfo)
資料項 |
欄位名稱 |
資料定義 |
必輸項 |
檢查規則 |
userId |
使用者ID |
Varchar(20) |
系統產生(UUID) |
單表唯一 |
userName |
使用者名稱稱 |
Varchar(8) |
手工輸入 |
不可為空 |
userAccount |
使用者帳戶 |
Varchar(20) |
手工輸入 |
全系統唯一 |
userMobile |
行動電話 |
Varchar(11) |
可以為空 |
|
isAdmin |
管理員標誌 |
DECIMAL(1,0) |
系統產生 |
1、超級管理員2、企業管理員3使用者 |
lockFlag |
帳號鎖定標誌 |
DECIMAL(1,0) |
系統產生 |
是否鎖定 1、鎖住 0、未鎖住 鎖定後的使用者不能登入系統 |
departId
|
所屬部門ID |
Varchar(20) |
手動選擇 |
來源t_sys_org表(orgId) |
departName |
部門名稱 |
Varchar(30) |
系統產生 |
|
orgId |
企業ID |
Varchar(20) |
系統產生 |
來源t_sys_org表(orgId) |
orgName |
企業名稱 |
Varchar(30) |
系統產生 |
來源t_sys_org表(orgName) |
createBy |
建立人ID |
Varchar(20) |
系統產生 |
|
createName |
建立人名稱 |
Varchar(30) |
系統產生 |
|
createTime |
建立時間 |
DATETIME
|
系統產生 |
|
updateBy
|
更新人ID |
Varchar(20) |
系統產生 |
|
updateName |
更新人名稱 |
Varchar(30) |
系統產生 |
|
lastUpdateTime |
更新時間 |
DATETIME |
系統產生 |
|
|
|
|
|
|
CREATE TABLE `t_sys_userInfo` (
`userId` VARCHAR(20) NOT NULL COMMENT '使用者主鍵',
`userName` VARCHAR(20) NOT NULL,
`orgId` VARCHAR(20) NOT NULL COMMENT '所屬機構ID',
`orgName` VARCHAR(50) NOT NULL COMMENT '所屬機構名稱',
`orgPath` VARCHAR(120) NOT NULL COMMENT '所屬機構路徑',
`userAccount` VARCHAR(16) NOT NULL COMMENT '登入帳號',
`userPwd` VARCHAR(16) NOT NULL COMMENT '登入密碼',
`userMobile` VARCHAR(11) NULL DEFAULT NULL COMMENT '行動電話',
`isAdmin` DECIMAL(1,0) NOT NULL DEFAULT '3' COMMENT '1、超級管理員2、企業管理員3使用者',
`lockFlag` DECIMAL(1,0) NOT NULL COMMENT '是否鎖住 1、鎖住 0、未鎖住',
`departId` VARCHAR(20) NOT NULL COMMENT '所屬部門',
`createBy` VARCHAR(20) NOT NULL,
`createName` VARCHAR(50) NOT NULL COMMENT '建立人',
`createTime` DATETIME NOT NULL COMMENT '建立時間',
`lastUpdateBy` VARCHAR(32) NOT NULL COMMENT '最後修改人ID',
`updateName` VARCHAR(50) NOT NULL COMMENT '最後修改人',
`lastUpdateTime` DATETIME NOT NULL COMMENT '最後修改時間',
PRIMARY KEY (`userId`)
)
COMMENT='使用者資訊表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
2. 資源管理(t_sys_resInfo)
資料項 |
欄位名稱 |
資料定義 |
必輸項 |
檢查規則 |
resId |
使用者ID |
Varchar(20) |
系統產生(UUID) |
單表唯一 |
resName |
使用者名稱稱 |
Varchar(20) |
手工輸入 |
不可為空 |
parentId |
使用者帳戶 |
Varchar(20) |
手工輸入 |
來源t_sys_resInfo表(resId) |
parentName |
行動電話 |
Varchar(20) |
可以為空 |
來源t_sys_resInfo表(resName) |
resType |
資源型別 |
DECIMAL(1,0) |
手動選擇 |
1、目錄2、選單 3.操作許可權 檢查規則: 1、目錄下面,不能新增操作許可權 2、選單下面不能新增目錄 3、以此類推
|
resState |
資源狀態 |
DECIMAL(1,0) |
手動選擇 |
0,不可用 1可用 |
resSort |
資源排序欄位 |
DECIMAL(1,0) |
系統產生 |
來源t_sys_org表(orgId) |
resUrl |
資源訪問地址 |
Varchar(30) |
手動輸入 |
後期自動產生 |
leafCount |
子級選單數量 |
DECIMAL(1,0) |
系統產生 |
|
resPath |
企業名稱 |
Varchar(30) |
系統產生 |
來源t_sys_org表(orgName) |
iconCls |
建立人ID |
Varchar(32) |
系統產生 |
|
CREATE TABLE `t_sys_resInfo` (
`resId` VARCHAR(32) NOT NULL COMMENT '主鍵ID',
`resName` VARCHAR(128) NOT NULL COMMENT '資源名稱',
`parentId` VARCHAR(32) NOT NULL COMMENT '資源父節點',
`parentName` VARCHAR(128) NOT NULL COMMENT '資源父節點名稱',
`resType` DECIMAL(1,0) NULL DEFAULT '1' COMMENT '1、功能選單 2、功能點 3、按鈕',
`resState` DECIMAL(1,0) NULL DEFAULT '1' COMMENT '記錄資源的狀態(可用,不可用):0表示不可用,1表示可用',
`resSort` DECIMAL(8,0) NULL DEFAULT '0' COMMENT '資源排序 ',
`resUrl` VARCHAR(512) NULL DEFAULT '' COMMENT '資源URL地址',
`leafCount` DECIMAL(1,0) NULL DEFAULT '0' COMMENT '子節點數量',
`resPath` VARCHAR(2048) NULL DEFAULT '' COMMENT '記錄資源節點的路徑:當前選單的上級選單,上級選單的父級選單',
`iconCls` VARCHAR(20) NULL DEFAULT '' COMMENT '資源圖示',
PRIMARY KEY (`resId`)
)
COMMENT='系統資源'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
3. 組織機構表(t_sys_org)
CREATE TABLE `t_sys_org` (
`orgId` VARCHAR(20) NOT NULL COMMENT '組織主鍵',
`orgName` VARCHAR(50) NOT NULL COMMENT '組織名稱',
`orgShortName` VARCHAR(30) NULL DEFAULT NULL COMMENT '組織簡稱',
`parentId` VARCHAR(32) NOT NULL COMMENT '組織父節點ID',
`parentName` VARCHAR(50) NOT NULL COMMENT '父節點編碼',
`orgType` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '組織的型別 1、企業 2、部門 3、分公司,4,支行',
`orgStatus` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '記錄組織的狀態是否啟用:0,停用/1,啟用',
`orgHisStatus` DECIMAL(1,0) NOT NULL DEFAULT '1' COMMENT '0,停用/1,啟用',
`orgLinkMan` VARCHAR(50) NULL DEFAULT NULL COMMENT '機構的法人代表名稱',
`orgTelephone` VARCHAR(20) NULL DEFAULT NULL COMMENT '機構的聯絡電話',
`orgFax` VARCHAR(20) NULL DEFAULT NULL COMMENT '機構的傳真',
`orgEmail` VARCHAR(100) NULL DEFAULT NULL COMMENT '機構的電子郵箱',
`orgAddress` VARCHAR(200) NULL DEFAULT NULL COMMENT '組織地址',
`orgWebsite` VARCHAR(200) NULL DEFAULT NULL COMMENT '組織的網站',
`leafCount` DECIMAL(1,0) NULL DEFAULT NULL COMMENT '子企業數量',
`orgSort` DECIMAL(10,0) NULL DEFAULT NULL COMMENT '組織排序',
`resIconStyle` VARCHAR(20) NULL DEFAULT '' COMMENT '資源圖示',
`orgPath` VARCHAR(2048) NULL DEFAULT NULL COMMENT '記錄組織的節點路徑',
`createBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '建立人ID',
`createName` VARCHAR(50) NULL DEFAULT NULL COMMENT '建立人',
`createTime` DATETIME NULL DEFAULT NULL COMMENT '建立時間',
`lastUpdateBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '最後修改人ID',
`updateName` VARCHAR(50) NULL DEFAULT NULL COMMENT '最後修改人',
`lastUpdateTime` DATETIME NULL DEFAULT NULL COMMENT '最後修改時間',
PRIMARY KEY (`orgId`)
)
COMMENT='組織架構資訊'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
4. 組織角色表(t_sys_role)
CREATE TABLE `t_sys_role` (
`roleId` VARCHAR(20) NOT NULL COMMENT '角色表主鍵ID',
`orgId` VARCHAR(20) NULL DEFAULT NULL COMMENT '所屬組織',
`orgPath` VARCHAR(20) NULL DEFAULT NULL COMMENT '組織路徑',
`orgName` VARCHAR(50) NOT NULL COMMENT '組織名稱',
`roleName` VARCHAR(50) NOT NULL COMMENT '角色名稱',
`roleDesc` VARCHAR(100) NULL DEFAULT NULL COMMENT '角色描述',
`createBy` VARCHAR(20) NOT NULL COMMENT '建立人ID',
`createName` VARCHAR(50) NOT NULL COMMENT '建立人',
`createTime` DATETIME NOT NULL COMMENT '建立時間',
`lastUpdateBy` VARCHAR(20) NULL DEFAULT NULL COMMENT '最後修改人ID',
`updateName` VARCHAR(50) NULL DEFAULT NULL COMMENT '最後修改人',
`lastUpdateTime` DATETIME NULL DEFAULT NULL COMMENT '最後修改時間',
PRIMARY KEY (`roleId`)
)
COMMENT='角色資訊表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
5. 使用者角色表(t_sys_userRole)
CREATE TABLE `t_sys_userRole` (
`userRoleId` VARCHAR(20) NOT NULL COMMENT '主鍵ID',
`roleId` VARCHAR(20) NULL DEFAULT NULL COMMENT '角色表主鍵ID',
`userId` VARCHAR(20) NULL DEFAULT NULL COMMENT '使用者主鍵',
PRIMARY KEY (`userRoleId`)
)
COMMENT='使用者角色關係表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
6. 角色資源表(t_sys_roleRes)
CREATE TABLE `t_sys_roleRes` (
`roleResId` VARCHAR(20) NOT NULL COMMENT '角色資源主鍵ID',
`roleId` VARCHAR(22) NOT NULL COMMENT '角色表主鍵ID',
`resId` VARCHAR(20) NOT NULL COMMENT '資源主鍵',
`isReadWrite` DECIMAL(1,0) NOT NULL DEFAULT 1 COMMENT '1,只讀取2,可讀寫',
PRIMARY KEY (`roleResId`)
)
COMMENT='角色資源關係表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
7. 企業資源表(t_sys_orgRes)
CREATE TABLE `t_sys_orgRes` (
`orgResId` VARCHAR(20) NOT NULL COMMENT '角色資源主鍵ID',
`orgId` VARCHAR(22) NOT NULL COMMENT '角色表主鍵ID',
`resId` VARCHAR(20) NOT NULL COMMENT '資源主鍵',
`isReadWrite` DECIMAL(1,0) NOT NULL DEFAULT 1 COMMENT '1,只讀取2,可讀寫',
PRIMARY KEY (`orgResId`)
)
COMMENT='角色資源關係表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
相關運營截圖:
轉載自-- https://www.cnblogs.com/jurendage/p/9120168.html