寫(xiě)程序,做產(chǎn)品,過(guò)日子

          成功其實(shí)很簡(jiǎn)單,就是強(qiáng)迫自己堅(jiān)持下去

          BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
            69 Posts :: 1 Stories :: 92 Comments :: 0 Trackbacks

          RBAC(基于角色的權(quán)限控制)是一個(gè)老話題了,但是這兩天我試圖設(shè)計(jì)一套表結(jié)構(gòu)實(shí)現(xiàn)完整的RBAC時(shí),發(fā)現(xiàn)存在很多困難。

          我說(shuō)的完整的RBAC,是指支持角色樹(shù)形結(jié)構(gòu)和角色分組。具體來(lái)說(shuō),應(yīng)當(dāng)包含如下權(quán)限控制需求:

          1. 父級(jí)角色可以訪問(wèn)甚至是修改其子級(jí)的數(shù)據(jù),包含直接子級(jí)直到最終子級(jí)。
          2. 角色可以訪問(wèn)其所在組的數(shù)據(jù)。
          3. 父級(jí)角色可以訪問(wèn)其所有子級(jí)(從直接子級(jí)到最終子級(jí))所在組的數(shù)據(jù)。

          而具體到我的系統(tǒng)中,還應(yīng)當(dāng)有如下需求。

          1. 兼容多種數(shù)據(jù)庫(kù)產(chǎn)品。只能用簡(jiǎn)單的表,視圖,存儲(chǔ)過(guò)程和函數(shù)等實(shí)現(xiàn)。
          2. 同時(shí)兼容單條數(shù)據(jù)處理和批量數(shù)據(jù)處理的需求。

          且不論這些具體需求,RBAC的基本表應(yīng)當(dāng)如下四個(gè):

          • roleList表,記錄所有的角色和角色組。
            • roleId: PK, 角色/組的ID,全局唯一,不區(qū)分角色和組。
            • roleName:角色/組的名稱。
            • roleType: R - 角色,G - 組
          • rolePermission表,記錄每一個(gè)角色/組對(duì)每一個(gè)對(duì)象的權(quán)限。
            • permissionID: PK, 無(wú)特定意義。
            • role: 角色/組的ID。
            • object: 對(duì)象的ID。
            • permission: 權(quán)限標(biāo)識(shí),如讀,寫(xiě),刪等。
          • roleRelationship表,記錄角色/組之間的關(guān)系。
            • relationId: PK, 無(wú)特定意義。
            • superiorRole: 父角色/組的ID。
            • role:子角色,子組,成員角色,成員組的ID。
            • relationship: 關(guān)系標(biāo)識(shí),可在如下設(shè)置集中選取一個(gè)。
              • PG標(biāo)識(shí):P - 父子關(guān)系,G - 組/成員關(guān)系。
              • PPGG標(biāo)識(shí):在PG集上,再加三種:PP - 間接父級(jí)關(guān)系,GG - 組內(nèi)組關(guān)系,CG - parentRole是組,childRole的子角色或間接子角色是其成員,或其子組(含間接子組)的成員
          • objectList表,記錄所有的對(duì)象。
            • objectId: PK,對(duì)象ID,全局唯一。
            • objectName: 對(duì)象名稱。
            • ... ...

          分析上述表結(jié)構(gòu),不難發(fā)現(xiàn),問(wèn)題的關(guān)鍵在于從rolePermission表中讀取數(shù)據(jù)時(shí),如何限定角色/組的范圍.

          方案一

          如果角色和組的總量不大,比如在100以內(nèi),采用PPGG標(biāo)識(shí)關(guān)系,讀取數(shù)據(jù)時(shí)是最快的。這個(gè)時(shí)候的SQL只需要一個(gè)輸入?yún)?shù)?roleId:

          SELECT object FROM rolePermission p left join roleRelationship r on p.role = r.role WHERE p.role = ?roleId or r.superiorRole = ?roleId. (尚未驗(yàn)證SQL的正確性)

          但是,這個(gè)方案是以極度冗余roleRelationship表的數(shù)據(jù)為代價(jià)的,比如有100個(gè)角色,那么roleRelationship中將會(huì)有100 * 100 =10,000條記錄。而在每次調(diào)整角色和R角色組的時(shí)候,就要在roleRelationship中一次增加或刪除100條記錄。這個(gè)開(kāi)銷(xiāo)是比較大的。

          方案二

          只標(biāo)識(shí)PG,查詢時(shí)接收的輸入?yún)?shù)為一個(gè)完整的相關(guān)角色列表?roleList。

          SELECT object FROM rolePermission WHERE role in (?roleList)

          在系統(tǒng)運(yùn)行時(shí),這個(gè)?roleList通常可以從role hierarchy cache中取到,比較方便。這個(gè)方案的主要問(wèn)題有二:

          1)如果?roleList過(guò)長(zhǎng),使用in判斷性能會(huì)很差。

          2)在有些情況下,如報(bào)表查詢和系統(tǒng)外查詢時(shí),取得roleList不太方便。

          方案三

          只標(biāo)識(shí)PG,但使用如下三個(gè)數(shù)據(jù)庫(kù)函數(shù)來(lái)判斷角色/組之間的關(guān)系。

          • boolean isChild(role, parentRole) - 如role為parentRole的子,返回true。
          • boolean isDescendant(role, ancestorRole) - 如role為ancestorRole的子或間接子級(jí),返回true。
          • boolean isMember(role, group) - 如role為group的成員或子組的成員,返回true。
          • boolean descendantIsMember(role, group) - 如role的子或間接子級(jí)為group的成員,返回true。
          • boolean isBelong(role, super) - 如role為super的子,間接子,成員或間接員,或者role的子(含間接子)是super的成員或子組成員,返回true。

          在查詢時(shí),也只需要接收一個(gè)?roleId:SELECT object FROM rolePemission WHERE isBelong(?roleId, role)

          如何寫(xiě)出高性能的數(shù)據(jù)庫(kù)函數(shù)是實(shí)現(xiàn)這個(gè)方法的關(guān)鍵。

          上述方法僅是理論分析,我傾向于方案二。

          終于想到新的方案了。

          方案四,

          結(jié)合方案一和方案二,在roleRelationship中,對(duì)前兩級(jí)(也可以是三級(jí)或四級(jí))角色,保存其所有的下級(jí)角色和組。這樣,如果以前兩級(jí)角色查詢數(shù)據(jù),就使用方案一,如果以第三級(jí)及以下的角色查詢數(shù)據(jù),就使用方案二。

          仍以100個(gè)角色為例,每個(gè)角色要保存三個(gè)關(guān)系:一級(jí)主管角色,二級(jí)主管角色,直接主管角色,最多有300條數(shù)據(jù)。

          每往角色組中加一個(gè)角色,也需要加入三條數(shù)據(jù):角色本身,一級(jí)主管角色,二級(jí)主管角色。

          但往角色組中加一個(gè)子組,需要加入的數(shù)據(jù)量就大一些:子組本身,子組所有角色,子組所有角色的一級(jí)主管角色和二級(jí)主管角色。如在多個(gè)子組中發(fā)現(xiàn)同一角色,可重復(fù)保存,但應(yīng)在表中附加說(shuō)明是由哪個(gè)子組導(dǎo)入的。這樣在刪除子組時(shí)就可以有選擇性的刪除。

          但重復(fù)子組的情況就比較麻煩,還有等考慮。假充有組g01,g11,g12,g21。g01包含g11和g12,g11和g12分別包含g21。從g01中刪除g11時(shí),如何判斷g21的去留?看來(lái)還是應(yīng)當(dāng)在維護(hù)時(shí)判斷應(yīng)不應(yīng)當(dāng)刪除。

          Technorati :

          posted on 2006-12-27 17:12 Welkin Hu 閱讀(6161) 評(píng)論(0)  編輯  收藏 所屬分類: MicrosoftJava
          主站蜘蛛池模板: 麻栗坡县| 潞城市| 图木舒克市| 娄底市| 项城市| 东台市| 抚宁县| 甘洛县| 莆田市| 天柱县| 永年县| 鄂托克旗| 沁阳市| 睢宁县| 含山县| 获嘉县| 永川市| 渭源县| 新营市| 泽普县| 昂仁县| 仪陇县| 襄樊市| 光山县| 铜陵市| 尚义县| 大姚县| 安丘市| 建宁县| 镇远县| 高淳县| 综艺| 昂仁县| 德惠市| 万源市| 留坝县| 滨州市| 洪雅县| 富蕴县| 江源县| 榆树市|