一、概要
通常,需要單獨的權限系統是解決授權的管理和維護,再分配等難題,不針對開發而言。
系統架構目標:在易于理解和管理,開發的前提下,滿足絕大部分粗粒度和細粒度權限控制的功能需要。
除了粗粒度權限,系統中必然還會包括無數對具體Instance的細粒度權限。這些問題,被留給對框架的擴展方法來解決,這樣的考慮基于以下兩點:
? 1、細粒度的權限判斷必須要在資源上獲取權限分配的支持的上下文信息才可能得以實現。
2、細粒度的權限常常具有相當大的業務邏輯相關性。對不同的業務邏輯,常常意味著完全不同的權限判定原則和策略。相比之下,粗粒度的權限更具通用性,將其實現為一個架構,更有重用價值;而將細粒度的權限判斷實現為一個架構級別的東西就顯得繁瑣,增加架構的復雜性。而且不是那么的有必要,用定制的代碼來實現就更簡潔,更靈活。否則會變成各種邏輯代碼的堆砌。
比如,product post數量的控制,這種一般要知道用戶個性化的信息,付錢數量到數據庫中查找最高數量,還要知道此用戶已經有多少產品等,規則不具備通用性和重用性,
?? 所以細粒度控制不應該放在權限架構層來解決。實例級的細粒度權限的解決方案就是將它轉化為粗粒度權限,這樣我們權限客戶端就變得很簡單了。
名詞解釋:
??? 粗粒度權限 :一般可以通過配置文件來授權,授權只有真假,沒有多少之分,不需要上下文的支持。
??? 不消耗資源的。
??? 邏輯表達式:判斷“Who對What(Which)進行How的操作”的邏輯表達式是否為真。
??? 別名:靜態授權、類級授權
?細粒度權限:不能通過配置文件等表達,需要特定上下文的支持.
??? 邏輯表達式:判斷“When(Where)的時候,Who對What(Which)進行How的操作”的邏輯表達式是否為真。
??? 別名:動態授權、實例級授權
設計原則 :
框架只提供粗粒度的權限。
細粒度的權限也需要集中管理和維護
細粒度的權限通過定制的擴展代碼將細粒度轉化為粗粒度授權。
二、權限系統的設計
權限往往是一個極其復雜的問題, 設計權限系統第一個要解決的問題就是什么樣的行為是需要權限控制,什么樣的是業務方法。他們之間本來是沒有明確的區分,任何權限從某種角度上說可以是一種業務方法。為了以后管理和開發方面我們從概念上需要將權限和業務明確劃分清楚,指導開發。
?權限控制行為:? 對What(Which)進行How的操作需要區分Who,具有Who身份差異性和可替換性。? 我們將此類操作作為權限。
???? 特點: 可以收回也可以分配的,具有一定的抽象級別。?????? 消耗資源,行為結果具備一些持久性的影響。
?業務邏輯行為:? 對What(Which)進行How的操作的時候與Who的身份無關或者具有Who身份差異性但???????????? 是不具有可替換性。
??? 特點: 不能抽象和共享,很難回收和分配。不消耗資源,不產生持久性。現實中也存在某一時期行為是業務邏輯,最后演變成權限控制,或者相反的過程。
1、粗粒度權限設計
?????? 采用自主型訪問控制方法,操作給予訪問控制列表。每一個用戶通過角色獲得一組權限集合,權限系統的功能是驗證用戶申請的權限(集合)是否在這個集合當中,即申請的權限(集合)是否投影在用戶擁有的權限集合,換句話說:只要某用戶直接或者間接的屬于某個Role那么它就具備這個Role的所有權限許可。
一個自主型訪問控制方法的權限系統包括以下幾個部分:角色、權限、訪問控制表、
l???????? 權限
描述一個權限可以通過以下幾個要素說明:
類型(class):
名稱(name):
動作(actions):
掩碼(mask):
屬性:
具體權限Example:
1、Test
類型(class):com.yangjs.secutiry. permissions. TestPermission
名稱(name):如:test.* ,test.sub.* ,test.sub1.sub2
動作(actions): brower_detail ,post,repost,……
掩碼(mask):0x1,0x2,0x4…..
屬性: 無
.…………..
l???????? 存取控制器(my--acl.xml)配置
存取控制項(ACE):角色到權限的映射集合,表示某個角色可以在某些資源上執行某些動作,它們之間通過role關聯(繼承),ACE之間產生包含關系。
存取控制列表(ACL):ACE的集合。
?我們的存取控制器(ACL)是通過一個xml的配置文件說明,存取控制列表由多個存取控制項(ACE)來描述。使用方法(略)
?2、細粒度權限設計
??? 細粒度授權需要上下文的支持,而且每個權限控制的上下問題都不一樣,這由相關的業務邏輯決定,而且此類授權一般變化較快,應此需要將強的可維護性和擴展性,支持變化,但又不能夠太復雜,否則缺乏可執行性。雖然此類權限個性化較強,我們仍然可以總結出很多共性:
1.?????? 幾乎所有的授權需要用戶的角色和ID.
2.?????? 特定的上下文幾乎都同用戶資源使用情況相關.
?? 我們將此類信息稱為UserState 即:User角色以及資源使用情況和當前狀態。大部分信息我們在用戶登陸的時候已經。獲得。授權貫穿Web層和Biz層,因此我們的登陸要獨立于Web端。因此上下文我們可以用UserState結合其他來抽象。
?? 關于上下文的維護問題,我們不可能將UserState此類參數在Web層和Biz層來回傳遞,更加不能在需要授權的地方都加上一個這樣的方法參數,這樣不太現實。其次如果在授權的地方再從數據庫中取一次這樣雖然能夠解決部分問題(不能解決userId的傳遞),這樣效率太低,不能接受。
?????? 解決方法就是將此類信息cache起來,用的時候再去取,由于此類信息具有非常高的并發性,對線程安全較高,因此我們決定將此類信息放入一個線程上下文的內存cache中。此外我們由于引入cache,就需要解決所有cache共有的維護性問題。
?????? Cache的生命周期:用戶的一次請求,屬于線程級,用戶請求線程結束,Cache結束。
?????? Cache的更新:當上下文信息發生變化是需要及時更新Cache,這是一個不可避免的步驟。
??????? Cache丟失:發生在如系統down機,線程崩潰,內存溢出等等,對用戶來說就是當前請求突然中斷。
?????? 當用戶重新發送請求,我們的系統就需要重新驗證用戶,此時我們可以更新Cache解
?????? 決丟失問題。
?????? Cache的清理:這個實現就是當用戶請求結束,返回應答的時候清理,可以通過Filter實現,比較簡單。
以上是相關的原理部分,我們看看系統地實現:
實現:線程上下文的cache
實現類:com.yangjs.cache.ThreadContextCache:
public class ThreadContextCache {
??? public static Map asMap();
??? public static boolean containsKey(Object key);
??? public static boolean containsValue(Object key);
??? public static Object get(Object key);
??? public static void put(Object key, Object value);
??? public static Object remove(Object key);
??? public static void clean();
public static int size() ;
public static void destroy()
posted on 2007-04-16 09:17
EricWong 閱讀(8768)
評論(7) 編輯 收藏 所屬分類:
Java