ITeye論壇中關於權限控制的帖子非常之精彩,現將其精華內容摘錄於下。
樓主關於權限控制的問題
1. 菜單級別
2. 頁面元素級別
3. 數據級別
目前好像用的比較多的是基於RBAC的,我經常用的也就是控制到菜單級別,對於控制頁面元素和數據級別用的不是很多,目前需要解決權限控制到頁面元素級別,網上看了很多但是不是很明白。不知大家有什麼好的解決方案沒有。大家的表都是怎樣設計的?希望高手們不吝指點,有什麼好的方案讓借鑑借鑑。
我的目前表主要就包括5張:
用戶表;角色表;菜單表(包括一級菜單、二級菜單) ;用戶和角色的關聯表(用戶角色多對多);角色和菜單的關聯表等。
RBAC(基於角色的訪問控制)掃盲貼
隨着系統的日益龐大,爲了方便管理,可引入角色組對角色進行分類管理,跟用戶組不同,角色組不參與授權。例如:某電網系統的權限管理模塊中,角色就是掛在區局下,而區局在這裏可當作角色組,它不參於權限分配。另外,爲方便上面各主表自身的管理與查找,可採用樹型結構,如菜單樹、功能樹等,當然這些可不需要參於權限分配。
george_space的“權限控制”的部分數據模型
有時候需要單獨爲一個用戶增加一兩個權限的,這時候單獨爲這個用戶設計一個“角色”,不值得,所以我設計的是:既可以通過角色爲用戶分配權限,也可以直接將權限分配給用戶。
--------------------------------------------
我接觸過的幾個開發人員,都不明白爲什麼要直接給用戶分配權限,但是在軟件的實際應用中,如果完全基於“角色”爲人員分配權限,你會 發現角色之間重複、冗餘的權限很多,這樣反覆的定義多種多樣的“角色”,還不如設計成可以直接爲人員分配權限呢。
--------------------------------------------
權限管理基本上分爲以下幾個步驟:
1、定義權限-》定義角色-》爲人員分配角色(或者直接分配權限),這是一個分配權限的過程;
--------------------------------------------
2、定義受保護資源-》爲“受保護資源”指定授權權限,這是一個授權的過程;
--------------------------------------------
3、應用程序請求“受保護資源”-》“受保護資源”的授權權限與人員持有的權限進行匹配-》匹配成功,允許訪問資源,匹配失敗,不允許訪問資源,這是一個認證的過程。
--------------------------------------------
上面這三個過程,是典型的“操作權限”的流程。
--------------------------------------------
關於“頁面元素”的控制,目前多數權限管理系統,都是用“自定義權限標籤”來控制頁面元素的顯示與否的。
我目前也是這樣實現的,但是我一直認爲:其實用“自定義權限標籤”來控制頁面元素的顯示與否,跟直接在視圖中使用程序邏輯判斷,是一樣的,並沒有做到“靈活配置”,當權限編碼改變,或者權限含義改變時,還是要去動頁面的標籤,所以跟寫死沒什麼分別。
如果頁面元素是通過服務端組裝成json,或者別的格式的數據,然後返回到視圖層進行渲染,這樣的話,就可以做到“頁面元素的權限靈活配置了”,可以通過數據庫定義那些按鈕對那些權限或角色進行顯示。
“服務端組裝視圖層組件,返回視圖層渲染”,這個模式雖然做到了“對頁面元素的權限靈活配置”,但是犧牲掉了很多東西,比如加大了服務端的複雜度,使得頁面的設計更加“程序員化”,而不是“美工化”等。
--------------------------------------------
至於最關鍵的“數據權限”,也就是人員對數據的讀取深度的控制,是更爲複雜的流程。
--------------------------------------------
對於“數據深度”的控制,我目前的做法是和業務結合的非常緊密,即:在讀取數據的程序中,比如“列表”頁,首先判斷當前登陸者有沒有“讀取任意深度的權限”,如果有,就不做讀取限制;如果沒有,則判斷當前登錄人員是不是部門主管,如果是,則遞歸讀取本部門下的所有數據,如果不是主管,則只讀取自己的數據。
--------------------------------------------
“數據深度”的控制,細設計的話,應該可以更通用,更靈活,大家有什麼更好的思路,可以討論一下。
--------------------------------------------
我目前設計的是一個人員只能有一個“角色”,當然,如果設計成一個人員有多個“角色”,也不是很複雜的事情,在“用戶表”和“角色表”之間增加一個“用戶-角色映射表”就可以了,但是爲了系統的簡單起見,我把這種設計簡化了。
--------------------------------------------
以下是我的“權限控制”的部分數據模型:
我目前比較關心的是:
1、數據權限(讀取數據的深度)有什麼更通用的設計?
2、頁面元素的控制,除了使用“自定義權限標籤”,或者“服務端組裝視圖層組件”兩種方法,還有沒有更好的設計?
sdnasky和george_space關於該問題的精彩探討
設計上的關鍵是找到權限控制點
界面級:自定義標籤可以實現
URL級:Filter可以實現
後臺方法級:AOP可以實現
數據級:良好設計+AOP可以實現
即使沒有良好的設計,針對不同需求,在控制點寫攔截處理類就行了,只是重複代碼的問題
權限的關鍵是:找到控制點,攔截,然後做你想做的事情
• sdnasky寫到:
• 界面級:自定義標籤可以實現
我現在也是使用自定義標籤來實現的界面元素控制:
- <eagle:hasPermission name="saveOrder">
- <input type="image" src="${rootUriOfCurrentPage}/resources/image/button/save-order.png" name="submit_top_button" id="submit_top_button" value="保存訂單" />
- </eagle:hasPermission>
問題:現在標籤中定義擁有“saveOrder”權限的人,可以看見保存訂單的按鈕,但是項目交給客戶以後,客戶想讓擁有“kissGirl”權限的人,也能看見保存訂單按鈕,那麼你是不是要去修改頁面?
這樣每次權限定義發生變動,都要去修改頁面自定義標籤,跟硬編碼寫死權限判斷有什麼分別?
• sdnasky寫到:
• 數據級:良好設計+AOP可以實現
問題:怎麼實現?這個是關鍵!
舉個簡單的例子:
一個列表頁,要求:普通員工看見自己發表的信息(標題、發佈時間);
部門經理看見本部門的信息(標題、發佈時間 + 發佈人積分);
管理員看見所有的信息(標題、發佈時間、發佈人積分 + 刪除/修改)按鈕。
這個列表頁是使用web service從美國加利福尼亞州總部讀取的,問,如何實現數據權限控制?
這樣的需求,不是一個小小的AOP攔截就能夠搞定的,即使能搞定,其複雜度也是超乎想象的。
有一個比較笨的方法,就是在服務端做權限邏輯判斷,組裝出當前權限應該看到的數據量和數據列,然後使用json
格式傳遞到視圖層進行渲染,這樣就相當於把視圖端自定義標籤所做的判斷,移動到了服務端。
服務端使用策略模式,針對不同的權限,執行不同的查詢邏輯;
如果有新的查詢邏輯出來,就更麻煩了,理論上可以使用“頁面上可視化配置 = > 動態生成java類 => 動態加載新的查詢邏輯類 => 動態執行新的查詢邏輯類”這樣的方式來把新邏輯插入當前的判斷中,但是這僅僅是理論上的設計,實際做起來,可不是上面這樣三言兩語能夠“說”完的。
要做到數據權限的精確控制,除了和系統緊密耦合的做法和硬編碼判斷的做法,我還沒有發現更好的實現,請樓下大牛們趕緊賜教。
- <eagle:hasPermission id="xxx.jsp.saveorder">
- <input type="image" src="${rootUriOfCurrentPage}/resources/image/button/save-order.png" name="submit_top_button" id="submit_top_button" value="保存訂單" />
- </eagle:hasPermission>
權限標識可以使用命名規則,用來區分不同類型權限:菜單,界面控件,或其他的
2.取數據的方法如果設計合理,預留了可以方便添加數據過濾的接口,用AOP攔截方法調用,修改輸入參數即可
即使設計不好,用AOP攔截方法調用(不調用現有方法),直接調用全新的含有數據過濾的取數據方法即可,無非是有重複代碼而已
補充一句不是“小小的AOP” AOP是非常強大的,它是代理模式,既然都給我代理,我就可以爲所欲爲(攔截調用,修改參數,修改返回值,甚至調用全新的方法),都爲所欲爲了,還不夠強大麼?
Html代碼
- <eagle:hasPermission id="user.customer.*,user.manager.*">
- <input type="image" src="${rootUriOfCurrentPage}/resources/image/button/save-order.png" name="submit_top_button" id="submit_top_button" value="保存訂單" />
- </eagle:hasPermission>
但是問題的關鍵是:如果現在客戶要求“user.teamleader.*”也能保存訂單,你是不是要把“user.teamleader.*”手動添加到權限標籤裏面去?是不是要改動視圖層頁面?是不是跟修改硬編碼也簡單不到哪裏去?
2、AOP方式沒有親身實踐過,不知道是否行得通,不做評論。
下面是我現在的初步設計,總體的意圖是將查詢邏輯留給軟件部署者來在界面中配置:
執行階段時序圖:
1. 頁面標識出該頁面保存按鈕權限id爲xxx.jsp.saveorder,誰擁有這個標識誰就能訪問,“擁有“saveOrder”權限的人”和“擁有“kissGirl”權限的人”都是角色,都不是最細緻的針對唯一權限標識點,不管你用什麼數據模型,找到 用戶-權限唯一標識 關係即可
2.如果美國總部“設計良好”提供了方便添加過濾條件的參數,AOP攔截調用修改傳入參數即可,即使美國總部是豬,沒關係,AOP獲得返回結果,針對返回結果編寫處理類,然後將處理之後的結果返回即可,至於界面上的“刪除/修改 按鈕”,留給界面級權限模塊處理,同上甚至有跟多要求,針對每一條數據處理都不一樣,比如張山可以“刪除/修改 按鈕”135條,李四可以“刪除/修改 按鈕”2468條,都沒問題,權限標識
xxx.jsp.deleteupdate.1
xxx.jsp.deleteupdate.2
xxx.jsp.deleteupdate.3
xxx.jsp.deleteupdate.4
xxx.jsp.deleteupdate.5
...
標識後接上ID即可,至於處理標籤如何處理,根據規則來就行了
最後共享一個這邊的權限設計
其他數據模型不看了
權限表含有3個字段
expression 可以爲空,該權限控制點的處理表達式
script 可以爲空,該權限控制點的處理表腳本
handle 可以爲空,該權限控制點的處理表類
系統需要引入腳本引擎,我們這裏用的是jbpm的腳本引擎,最後搞不定就只有反射處理類出馬了,不要指望用戶直接寫腳本,用戶最多自己寫簡單expression 什麼 money>10000 , level=經理 啥的,如果用戶有特殊需求,根據情況,我們寫好script或者handle提供用戶下拉選擇,填寫參數。
george_space, 關鍵是你們的權限標籤保存的不是權限點,而是角色,因此沒轍
權限標籤就是標識出,這塊範圍的權限標識就可以了,權限點跟角色的關係交給數據庫動態處理就行了
至於有無權限的判定處理,默認處理,表達式,腳本,處理類,各種工具提供選擇
也可以制定一個或若干個角色,或者使用role.*這樣的ant通配符,
我的權限系統是我自己設計的,因此不存在受制於人不便修改的問題。
如果有更好的實現方式,我很樂意及時來改進,關鍵是到現在爲止,我還沒發現比我的權限標籤更通用,更智能的“新標籤方式”
使用標籤方式控制頁面元素,本身就是一種硬編碼的變通寫法,如果再使用標籤來控制列表頁的列數量,那簡直就是硬編碼中的戰鬥硬,金剛石中的硬鑽頭,硬到無地自容了,沒有任何通用性可言。
使用權限標籤來定義頁面元素的顯示、隱藏,定義列表頁的列數量,這樣的做法只能適用於項目型軟件,不適用或者說不能完全適用於產品型軟件。
你說的標籤方式我理解,就是:
標籤定義一個ID="helloGirl" => 標籤實現類中判斷當前登錄者的權限列表,遍歷權限所管轄的所有頁面元素ID,看看是否包含本標籤的ID:helloGirl => 如果包含,顯示標籤body,如果不包含,不顯示標籤body
是不是這個意思?
如果權限id爲 xxx.jsp.xx.btnSave,你看不就解決了你的問題了麼
通配符應該作爲角色-權限關係存於數據庫,你們的問題就是由於通配符引起的,一個點就是一個點,要1對多就用數據庫存關係
爲什麼自定義權限標籤無法控制列?當然可以啦
每個列一個權限標識,有標識,顯示,沒有標識忽略
權限標籤加在populate單元格上
其他ITeye會員關於此問題的回覆
數據權限如果有兩個或更多維度的話應該如何處理呢?
比如:分地區、類型兩種維度
省日化經理只能看本省範圍內日化產品的銷售情況,城市經理能看到本市範圍全部商品的銷售情況等等
如果不同的角色對於同一個功能有不同的數據範圍要求,如何能設計一個良好的通用模型?
然後用戶角色就是RBAC,可以爲不同用戶分組形成UserGroup,可以爲不同權限分組形成Role
不懂的話可以參考Spring Security的實現。
、用戶組級的、域級別的...總之很多。
完全基於數據庫實現,有興趣的話自己找找wss/moss權限管理的文章看看
到現在爲止我也沒辦法解決。不放持久層分頁就會有多有少,要是少到一條都沒有就麻煩了。有一點的話 還糊弄的過去。
其他層次的問題 , 我全部通過AOP 攔截。有時候還要修改攔截的數據,反正搞的權限代碼也得理解業務,都不完美。
只是資源裏面的 可以多加一個 type 字段 類型可以是 url ,file 等
這樣會不會簡化了呢
前天一想寫這個玩意 ... 鬱悶 http://vb2005xu.iteye.com/blog/1136852
發現角色之間重複、冗餘的權限很多
關於這個 我說說我的解決方案 roles 表裏面加個 字段 parent_id 以此來實現 角色間的繼承
1.權限模型選型-基於角色控制的權限模型,組織機構模型等等
2.權限信息維護-尤其是分級權限管理和維護,這個很重要,要做到不失功能的前提下,儘量做的簡單實用、切忌複雜化,還要有強大的權限查詢和回收功能
3.權限控制api-這個一定要通俗易懂,而且要保證性能,可適當引入緩衝機制
4.權限緩衝同步和刷新-尤其是在集羣環境下
5.做到以上幾點的前提下,功能級權限和數據級權限就沒有問題了,爲了降低權限表的數據量,可以在通用權限維護管理的前提下增加按類別劃分存放權限數據表的功能
至於權限的劃分,應該可以劃分爲以下三大類:
1.功能權限-系統菜單,頁面功能操作點
2.數據權限-業務數據範圍權限
3.管理權限-管理功能權限和數據權限的權限
推薦一款開源產品——ralasafe權限管理中間件,內部也是使用規則對數據級策略進行描述。ralasafe還提供了圖形界面來實現規則的圖形化配置,不必手寫配置。
http://www.ralasafe.cn
但是這裏還是又一個問題。就是這樣做違背了RBAC的模型,我引用了ralasafe權限中間件其中一位commiter的話:“主體和資源種類很多時候,權限控制條目則急劇膨脹條目是N(主體)*N(資源),顯然需要有針對性的尋找規律進行分解從而減少數目,可以發現的是如果通過定義有限的角色(R)來替代主體授權則條目數量變化爲N*R+R*M,顯然角色數量是遠遠小於主體數量的,從而能夠達到簡化的母的。這就是RBAC得來源”。因此把上面的用戶全部換成角色,基於角色的訪問控制將很好的防止了權限的冗餘 後期維護也方便。 所以基於頁面級的權限控制 我們建議將控制點設置爲權限ID或叫資源ID,george_space提出的基於規則的命名 這個後期維護起來將會省很大的力氣,另外實現類 就根據權限ID去role_privilege表裏查找所有的角色,遍歷該角色 查找上下文中用戶是否在這些角色中。 ralasafe嚴格按照RBAC模型 並基於策略的模型實現數據集權限。 網址:www.ralasafe.cn 共同關注。