引子
最近要開發(fā)一個(gè)新的系統(tǒng),系統(tǒng)里面可以有許多不同的社區(qū)奈泪,每個(gè)社區(qū)下面有不同的項(xiàng)目适贸。項(xiàng)目和項(xiàng)目、社區(qū)和社區(qū)之間都是相互獨(dú)立的涝桅。我所做的工作是設(shè)計(jì)一套權(quán)限管理系統(tǒng)拜姿,這套系統(tǒng)允許不同的用戶在不同的社區(qū)或者項(xiàng)目之中有不同的權(quán)限,可以保證用戶無法做出越權(quán)的操作苹支。
經(jīng)過了一番努力,設(shè)計(jì)出了一套基于RBAC的分權(quán)分域的用戶權(quán)限系統(tǒng)误阻。
首先介紹一下什么是RBAC:
以角色為基礎(chǔ)的訪問控制(英語:Role-based access control, RBAC)债蜜,是資訊安全領(lǐng)域中,一種較新且廣為使用的訪問控制機(jī)制究反,其不同于強(qiáng)制訪問控制以及自由選定訪問控制直接賦予使用者權(quán)限寻定,而是將權(quán)限賦予角色。1996年精耐,萊威·桑度(Ravi Sandhu)等人在前人的理論基礎(chǔ)上狼速,提出以角色為基礎(chǔ)的訪問控制模型,故該模型又被稱為RBAC96卦停。之后向胡,美國國家標(biāo)準(zhǔn)局重新定義了以角色為基礎(chǔ)的訪問控制模型,并將之納為一種標(biāo)準(zhǔn)惊完,稱之為NIST RBAC僵芹。
以角色為基礎(chǔ)的訪問控制模型是一套較強(qiáng)制訪問控制以及自由選定訪問控制更為中性且更具靈活性的訪問控制技術(shù)。
在一個(gè)組織中小槐,會(huì)因?yàn)椴煌淖鳂I(yè)功能產(chǎn)生不同的角色拇派,執(zhí)行某項(xiàng)操作的權(quán)限會(huì)被賦予特定的角色。組織成員或者工作人員(抑或其它系統(tǒng)用戶)則被賦予不同的角色,這些用戶通過被賦予角色來取得執(zhí)行某項(xiàng)計(jì)算機(jī)系統(tǒng)功能的權(quán)限件豌。
- S = 主體 = 一名使用者或自動(dòng)代理人
- R = 角色 = 被定義為一個(gè)授權(quán)等級(jí)的工作職位或職稱
- P = 權(quán)限 = 一種存取資源的方式
- SE = 會(huì)期 = S疮方,R或P之間的映射關(guān)系
- SA = 主體指派
- PA = 權(quán)限指派
- RH = 角色階層。能被表示為:≥(x ≥ y 代表 x 繼承 y 的權(quán)限)
- 一個(gè)主體可對(duì)應(yīng)多個(gè)角色茧彤。
- 一個(gè)角色可對(duì)應(yīng)多個(gè)主體骡显。
- 一個(gè)角色可擁有多個(gè)權(quán)限。
- 一種權(quán)限可被分配給許多個(gè)角色棘街。
- 一個(gè)角色可以有專屬于自己的權(quán)限蟆盐。
數(shù)據(jù)庫結(jié)構(gòu)設(shè)計(jì)
項(xiàng)目使用的mysql數(shù)據(jù)庫,設(shè)計(jì)表格的大體結(jié)構(gòu)如下:
藍(lán)底模塊為基本表遭殉,黃底模塊為關(guān)系表石挂。
基本表有
- t_user
- t_role
- t_permission
- t_operation
關(guān)系表有
- t_user_role_community
- t_user_role_project
- t_role_permission
- t_permission_operation
權(quán)限判斷的主要思路是根據(jù)用戶傳過來的社區(qū)ID/項(xiàng)目ID+用戶ID+發(fā)起的請(qǐng)求路徑,通過多表聯(lián)查险污,來確定用戶在對(duì)應(yīng)的社區(qū)/項(xiàng)目內(nèi)所對(duì)應(yīng)的角色是否具有權(quán)限執(zhí)行響應(yīng)請(qǐng)求的操作痹愚。
由于在域方面,有社區(qū)和項(xiàng)目兩個(gè)尺度蛔糯,其中社區(qū)包含項(xiàng)目拯腮。但是由于一些其他原因,在社區(qū)表中無法表示出與項(xiàng)目的從屬關(guān)系蚁飒,只能把t_user_role表復(fù)用动壤,分身成兩張表:t_user_role_community和t_user_role_project。
由于我們的鑒權(quán)系統(tǒng)整個(gè)流程都是一對(duì)多的關(guān)系淮逻,即一個(gè)用戶可能對(duì)應(yīng)多個(gè)角色琼懊,一個(gè)角色可能對(duì)應(yīng)多種權(quán)限,一種權(quán)限又能對(duì)應(yīng)多種操作爬早。因此哼丈,一個(gè)用戶能對(duì)應(yīng)N多種操作,同時(shí)筛严,由于中間的多重映射關(guān)系醉旦,一個(gè)用戶對(duì)某個(gè)操作可能會(huì)對(duì)應(yīng)多次。
我們采用多表聯(lián)查的方式桨啃,輸入項(xiàng)為用戶+操作(操作具體表示為request的method+url)车胡,使用如下SQL語句進(jìn)行查詢,只要查詢結(jié)果不為空照瘾,即證明用戶有相應(yīng)的操作權(quán)限:
SELECT
*
FROM
t_user_role_community
INNER JOIN t_role_permission
INNER JOIN t_permission_operation ON t_user_role_community.strRole = t_role_permission.strRole
AND t_role_permission.nPermission = t_permission_operation.nPermission
WHERE
nUser = 10025
AND nCommunity = 1
AND strMethod = 'get'
AND strUrl = '/api/t_service'
這樣做實(shí)際上只查詢了社區(qū)線的權(quán)限吨拍,此外還有項(xiàng)目線的權(quán)限以及非社區(qū)非項(xiàng)目線的權(quán)限(例如個(gè)人中心、系統(tǒng)管理之類的网杆,我們把這部分的域直接設(shè)置為nCommunity=0羹饰,即項(xiàng)目編號(hào)為0)伊滋,想要覆蓋所有的域,我們相當(dāng)于要同時(shí)多表聯(lián)查三次队秩,只要其中任意一次能夠查到數(shù)據(jù)笑旺,則表明用戶有執(zhí)行該操作的權(quán)限。我們可以用UNION語句來實(shí)現(xiàn):
(SELECT
*
FROM
t_user_role_community
INNER JOIN t_role_permission
INNER JOIN t_permission_operation ON t_user_role_community.strRole = t_role_permission.strRole
AND t_role_permission.nPermission = t_permission_operation.nPermission
WHERE
nUser = 10025
AND (nCommunity = 0 OR nCommunity = 0)
AND strMethod = 'get'
AND strUrl = '/api/t_service')
UNION
(SELECT
*
FROM
t_user_role_project
INNER JOIN t_role_permission
INNER JOIN t_permission_operation ON t_user_role_project.strRole = t_role_permission.strRole
AND t_role_permission.nPermission = t_permission_operation.nPermission
WHERE
nUser = 10025
AND nProject = 0
AND strMethod = 'get'
AND strUrl = '/api/t_service')
好啦馍资,這就實(shí)現(xiàn)了一個(gè)相對(duì)完整的分權(quán)分域的系統(tǒng)啦~
結(jié)語
整個(gè)鑒權(quán)過程是放在后臺(tái)以中間件的形式存在的筒主。所有發(fā)送的請(qǐng)求都要經(jīng)過鑒權(quán)中間件才能繼續(xù)往后走下去。
因此鸟蟹,除了在數(shù)據(jù)庫層面進(jìn)行設(shè)計(jì)以外乌妙,還要在后臺(tái)代碼進(jìn)行一些必要性的優(yōu)化。比如說有一類操作的對(duì)應(yīng)權(quán)限是通用權(quán)限建钥,這類接口占所有接口的一半以上藤韵。因此在鑒權(quán)中間件我會(huì)先判斷一步是否為通用權(quán)限,若是則跳過接下來的鑒權(quán)熊经,直接判過泽艘;不是的話再按照既定流程繼續(xù)鑒權(quán)。
也可以在鑒權(quán)層增加日志打印镐依,把所有經(jīng)過鑒權(quán)的請(qǐng)求記錄在案匹涮,以便日后追蹤。
寫到這里突然發(fā)現(xiàn)槐壳,我這個(gè)前端然低,越做越往后了...