Java生鮮電商平臺-RBAC系統權限的設計與架構數據庫
說明:根據上面的需求描述以及對需求的分析,咱們得知一般的一箇中小型系統對於權限系統所需實現的功能以及非功能性的需求,在下面咱們將根據需求從技術角度上分析實現的策略以及基於目前兩種比較流行的權限設計思想來討論關於權限系統的實現。緩存
1.1. 技術策略安全
l 身份認證服務器
在B/S的系統中,爲識別用戶身份,一般使用的技術策略爲將用戶的身份記錄在Session中,也就是當用戶登陸時即獲取用戶的身份信息,並將其記錄到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與傳統訪問控制的差異在於增長一層間接性帶來了靈活性,RBAC一、RBAC二、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模型有必定的
出入,並且在數據權限的校驗上實現起來是很是的低效。
最終根聽說明,設計以下系統架構圖:
數據項 |
字段名稱 |
數據定義 |
必輸項 |
檢查規則 |
userId |
用戶ID |
Varchar(20) |
系統產生(UUID) |
單表惟一 |
userName |
用戶名稱 |
Varchar(8) |
手工輸入 |
不可爲空 |
userAccount |
用戶賬戶 |
Varchar(20) |
手工輸入 |
全系統惟一 |
userMobile |
移動電話 |
Varchar(11) |
能夠爲空 |
|
isAdmin |
管理員標誌 |
DECIMAL(1,0) |
系統產生 |
一、超級管理員二、企業管理員3用戶 |
lockFlag |
賬號鎖定標誌 |
DECIMAL(1,0) |
系統產生 |
是否鎖定 一、鎖住 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 '一、超級管理員二、企業管理員3用戶',
`lockFlag` DECIMAL(1,0) NOT NULL COMMENT '是否鎖住 一、鎖住 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
;
數據項 |
字段名稱 |
數據定義 |
必輸項 |
檢查規則 |
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) |
手動選擇 |
一、目錄二、菜單 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 '一、功能菜單 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
;
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 '組織的類型 一、企業 二、部門 三、分公司,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
;
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
;
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;
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
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
相關運營截圖: