?前言: ?
? 權限往往是一個極其復雜的問題,但也可簡單表述為這樣的邏輯表達式:判斷“Who對What(Which)進行How的操作”的邏輯表達式是否為真。針對不同的
應用
,需要根據項目的實際情況和具體架構,在維護性、靈活性、完整性等N多個方案之間比較權衡,選擇符合的方案。 ?
? 目標: ?
? 直觀,因為系統最終會由最終用戶來維護,權限分配的直觀和容易理解,顯得比較重要,系統不辭勞苦的實現了組的繼承,除了功能的必須,更主要的就是因為它足夠直觀。 ?
? 簡單,包括概念數量上的簡單和意義上的簡單還有功能上的簡單。想用一個權限系統解決所有的權限問題是不現實的。設計中將常常變化的“定制”特點比較強的部分判斷為業務邏輯,而將常常相同的“通用”特點比較強的部分判斷為權限邏輯就是基于這樣的思路。 ?
? 擴展,采用可繼承在擴展上的困難。的Group概念在支持權限以組方式定義的同時有效避免了重定義時 ?
? 現狀: ?
? 對于在企業環境中的訪問控制
方法
,一般有三種: ?
? 1.自主型訪問控制方法。目前在我國的大多數的信息系統中的訪問控制模塊中基本是借助于自主型訪問控制方法中的訪問控制列表(ACLs)。 ?
? 2.強制型訪問控制方法。用于多層次安全級別的
軍事
應用。 ?
? 3.基于角色的訪問控制方法(RBAC)。是目前公認的解決大型企業的統一資源訪問控制的有效方法。其顯著的兩大特征是:1.減小授權管理的復雜性,降低管理開銷。2.靈活地支持企業的安全策略,并對企業的變化有很大的伸縮性。 ?
? 名詞: ?
? 粗粒度:表示類別級,即僅考慮對象的類別(the ? type ? of ? object),不考慮對象的某個特 ?
? 定實例。比如,用戶管理中,創建、刪除,對所有的用戶都一視同仁,并不區分操作的具體對象實例。 ?
? 細粒度:表示實例級,即需要考慮具體對象的實例(the ? instance ? of ? object),當然,細 ?
? 粒度是在考慮粗粒度的對象類別之后才再考慮特定實例。比如,合同管理中,列表、刪除,需要區分該合同實例是否為當前用戶所創建。 ?
? 原則: ?
? 權限邏輯配合業務邏輯。即權限系統以為業務邏輯提供服務為目標。相當多細粒度的權限問題因其極其獨特而不具通用意義,它們也能被理解為是“業務邏輯”的一部分。比如,要求:“合同資源只能被它的創建者刪除,與創建者同組的用戶可以修改,所有的用戶能夠瀏覽”。這既可以認為是一個細粒度的權限問題,也可以認為是一個業務邏輯問題。在這里它是業務邏輯問題,在整個權限系統的架構設計之中不予過多考慮。當然,權限系統的架構也必須要能支持這樣的控制判斷。或者說,系統提供足夠多但不是完全的控制
能力
。即,設計原則歸結為:“系統只提供粗粒度的權限,細粒度的權限被認為是業務邏輯的職責”。 ?
? 需要再次強調的是,這里表述的權限系統僅是一個“不完全”的權限系統,即,它不提供所有關于權限的問題的解決方法。它提供一個基礎,并解決那些具有“共性”的(或者說粗粒度的)部分。在這個基礎之上,根據“業務邏輯”的獨特權限需求,編碼實現剩余部分(或者說細粒度的)部分,才算完整?;氐綑嘞薜膯栴}公式,通用的設計僅解決了Who+What+How ? 的問題,其他的權限問題留給業務邏輯解決。 ?
? 概念: ?
? Who:權限的擁用者或主體(Principal、User、Group、Role、Actor等等) ?
? What:權限針對的對象或資源(Resource、Class)。 ?
? How:具體的權限(Privilege, ? 正向授權與負向授權)。 ?
? Role:是角色,擁有一定數量的權限。 ?
? Operator:操作。表明對What的How ? 操作。 ?
? 說明: ?
? User:與 ? Role ? 相關,用戶僅僅是純粹的用戶,權限是被分離出去了的。User是不能與 ? Privilege ? 直接相關的,User ? 要擁有對某種資源的權限,必須通過Role去關聯。解決 ? Who ? 的問題。 ?
? Resource:就是系統的資源,比如部門新聞,文檔等各種可以被提供給用戶訪問的對象。資源可以反向包含自身,即樹狀結構,每一個資源節點可以與若干指定權限類別相關可定義是否將其權限應用于子節點。 ?
? Privilege:是Resource ? Related的權限。就是指,這個權限是綁定在特定的資源實例上的。比如說部門新聞的發布權限,叫做"部門新聞發布權限"。這就表明,該Privilege是一個發布權限,而且是針對部門新聞這種資源的一種發布權限。Privilege是由Creator在做開發時就確定的。權限,包括系統定義權限和用戶自定義權限用戶自定義權限之間可以指定排斥和包含關系(如:讀取,修改,管理三個權限,管理 ? 權限 ? 包含 ? 前兩種權限)。Privilege ? 如"刪除" ? 是一個抽象的名詞,當它不與任何具體的 ? Object ? 或 ? Resource ? 綁定在一起時是沒有任何意義的。拿新聞發布來說,發布是一種權限,但是只說發布它是毫無意義的。因為不知道發布可以操作的對象是什么。只有當發布與新聞結合在一起時,才會產生真正的 ? Privilege。這就是 ? Privilege ? Instance。權限系統根據需求的不同可以延伸生很多不同的版本。 ?
? Role:是粗粒度和細粒度(業務邏輯)的接口,一個基于粗粒度控制的權限框架軟件,對外的接口應該是Role,具體業務實現可以直接繼承或拓展豐富Role的內容,Role不是如同User或Group的具體實體,它是接口概念,抽象的通稱。 ?
? Group:用戶組,權限分配的單位與載體。權限不考慮分配給特定的用戶。組可以包括組(以實現權限的繼承)。組可以包含用戶,組內用戶繼承組的權限。Group要實現繼承。即在創建時必須要指定該Group的Parent是什么Group。在粗粒度控制上,可以認為,只要某用戶直接或者間接的屬于某個Group那么它就具備這個Group的所有操作許可。細粒度控制上,在業務邏輯的判斷中,User僅應關注其直接屬于的Group,用來判斷是否“同組” ? 。Group是可繼承的,對于一個分級的權限實現,某個Group通過“繼承”就已經直接獲得了其父Group所擁有的所有“權限集合”,對這個Group而言,需要與權限建立直接關聯的,僅是它比起其父Group需要“擴展”的那部分權限。子組繼承父組的所有權限,規則來得更簡單,同時意味著管理更容易。為了更進一步實現權限的繼承,最直接的就是在Group上引入“父子關系”。 ?
? User與Group是多對多的關系。即一個User可以屬于多個Group之中,一個Group可以包括多個User。子Group與父Group是多對一的關系。Operator某種意義上類似于Resource ? + ? Privilege概念,但這里的Resource僅包括Resource ? Type不表示Resource ? Instance。Group ? 可以直接映射組織結構,Role ? 可以直接映射組織結構中的業務角色,比較直觀,而且也足夠靈活。Role對系統的貢獻實質上就是提供了一個比較粗顆粒的分配單位。 ?
? Group與Operator是多對多的關系。各概念的關系圖示如下: ?
? 解釋: ?
? Operator的定義包括了Resource ? Type和Method概念。即,What和How的概念。之所以將What和How綁定在一起作為一個Operator概念而不是分開建模再建立關聯,這是因為很多的How對于某What才有意義。比如,發布操作對新聞對象才有意義,對用戶對象則沒有意義。 ?
? How本身的意義也有所不同,具體來說,對于每一個What可以定義N種操作。比如,對于合同這類對象,可以定義創建操作、提交操作、檢查沖突操作等??梢哉J為,How概念對應于每一個商業方法。其中,與具體用戶身份相關的操作既可以定義在操作的業務邏輯之中,也可以定義在操作級別。比如,創建者的瀏覽視圖與普通用戶的瀏覽視圖要求內容不同。既可以在外部定義兩個操作方法,也可以在一個操作方法的內部根據具體邏輯進行處理。具體應用哪一種方式應依據實際情況進行處理。
?
這樣的架構,應能在易于理解和管理的情況下,滿足絕大部分粗粒度權限控制的功能需要。但是除了粗粒度權限,系統中必然還會包括無數對具體Instance的細粒度權限。這些問題,被留給業務邏輯來解決,這樣的考慮基于以下兩點: ?
? 一方面,細粒度的權限判斷必須要在資源上建模權限分配的支持信息才可能得以實現。比如,如果要求創建者和普通用戶看到不同的信息內容,那么,資源本身應該有其創建者的信息。另一方面,細粒度的權限常常具有相當大的業務邏輯相關性。對不同的業務邏輯,常常意味著完全不同的權限判定原則和策略。相比之下,粗粒度的權限更具通用性,將其實現為一個架構,更有重用價值;而將細粒度的權限判斷實現為一個架構級別的東西就顯得繁瑣,而且不是那么的有必要,用定制的代碼來實現就更簡潔,更靈活。 ?
? 所以細粒度控制應該在底層解決,Resource在實例化的時候,必需指定Owner和GroupPrivilege在對Resource進行操作時也必然會確定約束類型:究竟是OwnerOK還是GroupOK還是AllOK。Group應和Role嚴格分離User和Group是多對多的關系,Group只用于對用戶分類,不包含任何Role的意義;Role只授予User,而不是Group。如果用戶需要還沒有的多種Privilege的組合,必須新增Role。Privilege必須能夠訪問Resource,同時帶User參數,這樣權限控制就完備了。 ?
? 思想: ?
? 權限系統的核心由以下三部分構成:1.創造權限,2.分配權限,3.使用權限,然后,系統各部分的主要參與者對照如下:1.創造權限 ? - ? Creator創造,2.分配權限 ? - ? Administrator ? 分配,3.使用權限 ? - ? User: ?
? 1. ? Creator ? 創造 ? Privilege, ? Creator ? 在設計和實現系統時會劃分,一個子系統或稱為模塊,應該有哪些權限。這里完成的是 ? Privilege ? 與 ? Resource ? 的對象聲明,并沒有真正將 ? Privilege ? 與具體Resource ? 實例聯系在一起,形成Operator。 ?
? 2. ? Administrator ? 指定 ? Privilege ? 與 ? Resource ? Instance ? 的關聯。在這一步, ? 權限真正與資源實例聯系到了一起, ? 產生了Operator(Privilege ? Instance)。Administrator利用Operator這個基本元素,來創造他理想中的權限模型。如,創建角色,創建用戶組,給用戶組分配用戶,將用戶組與角色關聯等等...這些操作都是由 ? Administrator ? 來完成的。 ?
? 3. ? User ? 使用 ? Administrator ? 分配給的權限去使用各個子系統。Administrator ? 是用戶,在他的心目中有一個比較適合他管理和維護的權限模型。于是,程序員只要回答一個問題,就是什么權限可以訪問什么資源,也就是前面說的 ? Operator。程序員提供 ? Operator ? 就意味著給系統穿上了盔甲。Administrator ? 就可以按照他的意愿來建立他所希望的權限框架可以自行增加,刪除,管理Resource和Privilege之間關系??梢宰孕性O定用戶User和角色Role的對應關系。(如果將 ? Creator看作是 ? Basic ? 的發明者, ? Administrator ? 就是 ? Basic ? 的使用者,他可以做一些腳本式的編程) ? Operator是這個系統中最關鍵的部分,它是一個紐帶,一個系在Programmer,Administrator,User之間的紐帶。 ?
? 用一個功能模塊來舉例子。 ?
? 一.建立角色功能并做分配: ?
? 1.如果現在要做一個員工管理的模塊(即Resources),這個模塊有三個功能,分別是:增加,修改,刪除。給這三個功能各自分配一個ID,這個ID叫做功能代號: ?
? Emp_addEmp,Emp_deleteEmp,Emp_updateEmp。 ?
? 2.建立一個角色(Role),把上面的功能代碼加到這個角色擁有的權限中,并保存到數據庫中。角色包括系統管理員,測試人員等。 ?
? 3.建立一個員工的賬號,并把一種或幾種角色賦給這個員工。比如說這個員工既可以是公司管理人員,也可以是測試人員等。這樣他登錄到系統中將會只看到他擁有權限的那些模塊。 ?
? 二.把身份信息加到Session中。 ?
? 登錄時,先到數據庫中查找是否存在這個員工,如果存在,再根據員工的sn查找員工的權限信息,把員工所有的權限信息都入到一個Hashmap中,比如就把上面的Emp_addEmp等放到這個Hashmap中。然后把Hashmap保存在一個UserInfoBean中。最后把這個UserInfoBean放到Session中,這樣在整個程序的運行過程中,系統隨時都可以取得這個用戶的身份信息。 ?
? 三.根據用戶的權限做出不同的顯示。 ?
? 可以對比當前員工的權限和給這個菜單分配的“功能ID”判斷當前用戶是否有打開這個菜單的權限。例如:如果保存員工權限的Hashmap中沒有這三個ID的任何一個,那這個菜單就不會顯示,如果員工的Hashmap中有任何一個ID,那這個菜單都會顯示。 ? ?
? 對于一個新聞系統(Resouce),假設它有這樣的功能(Privilege):查看,發布,刪除,修改;假設對于刪除,有"新聞系統管理者只能刪除一月前發布的,而超級管理員可刪除所有的這樣的限制,這屬于業務邏輯(Business ? logic),而不屬于用戶權限范圍。也就是說權限負責有沒有刪除的Permission,至于能刪除哪些內容應該根據UserRole ? or ? UserGroup來決定(當然給UserRole ? or ? UserGroup分配權限時就應該包含上面兩條業務邏輯)。 ?
? 一個用戶可以擁有多種角色,但同一時刻用戶只能用一種角色進入系統。角色的劃分方法可以根據實際情況劃分,按部門或機構進行劃分的,至于角色擁有多少權限,這就看系統管理員賦給他多少的權限了。用戶—角色—權限的關鍵是角色。用戶登錄時是以用戶和角色兩種屬性進行登錄的(因為一個用戶可以擁有多種角色,但同一時刻只能扮演一種角色),根據角色得到用戶的權限,登錄后進行初始化。這其中的技巧是同一時刻某一用戶只能用一種角色進行登錄。 ?
? 針對不同的“角色”動態的建立不同的組,每個項目建立一個單獨的Group,對于新的項目,建立新的 ? Group ? 即可。在權限判斷部分,應在商業方法上予以控制。比如:不同用戶的“操作能力”是不同的(粗粒度的控制應能滿足要求),不同用戶的“可視區域”是不同的(體現在對被操作的對象的權限數據,是否允許當前用戶訪問,這需要對業務數據建模的時候考慮權限控制需要)。???
?
擴展性: ?
? 有了用戶/權限管理的基本框架,Who(User/Group)的概念是不會經常需要擴展的。變化的可能是系統中引入新的 ? What ? (新的Resource類型)或者新的How(新的操作方式)。那在三個基本概念中,僅在Permission上進行擴展是不夠的。這樣的設計中Permission實質上解決了How ? 的問題,即表示了“怎樣”的操作。那么這個“怎樣”是在哪一個層次上的定義呢?將Permission定義在“商業方法”級別比較合適。比如,發布、購買、取消。每一個商業方法可以意味著用戶進行的一個“動作”。定義在商業邏輯的層次上,一方面保證了數據訪問代碼的“純潔性”,另一方面在功能上也是“足夠”的。也就是說,對更低層次,能自由的訪問數據,對更高層次,也能比較精細的控制權限。 ?
? 確定了Permission定義的合適層次,更進一步,能夠發現Permission實際上還隱含了What的概念。也就是說,對于What的How操作才會是一個完整的Operator。比如,“發布”操作,隱含了“信息”的“發布”概念,而對于“商品”而言發布操作是沒有意義的。同樣的,“購買”操作,隱含了“商品”的“購買”概念。這里的綁定還體現在大量通用的同名的操作上,比如,需要區分“商品的刪除”與“信息的刪除”這兩個同名為“刪除”的不同操作。 ?
? 提供權限系統的擴展能力是在Operator ? (Resource ? + ? Permission)的概念上進行擴展。Proxy ? 模式是一個非常合適的實現方式。實現大致如下:在業務邏輯層(EJB ? Session ? Facade ? [Stateful ? SessionBean]中),取得該商業方法的Methodname,再根據Classname和 ? Methodname ? 檢索Operator ? 數據,然后依據這個Operator信息和Stateful中保存的User信息判斷當前用戶是否具備該方法的操作權限。 ?
? 應用在 ? EJB ? 模式下,可以定義一個很明確的 ? Business層次,而一個Business ? 可能意味著不同的視圖,當多個視圖都對應于一個業務邏輯的時候,比如,Swing ? Client以及 ? Jsp ? Client ? 訪問的是同一個 ? EJB ? 實現的 ? Business。在 ? Business ? 層上應用權限較能提供集中的控制能力。實際上,如果權限系統提供了查詢能力,那么會發現,在視圖層次已經可以不去理解權限,它只需要根據查詢結果控制界面就可以了。 ?
? 靈活性: ?
? Group和Role,只是一種輔助實現的手段,不是必需的。如果系統的Role很多,逐個授權違背了“簡單,方便”的目的,那就引入Group,將權限相同的Role組成一個Group進行集中授權。Role也一樣,是某一類Operator的集合,是為了簡化針對多個Operator的操作。 ?
? Role把具體的用戶和組從權限中解放出來。一個用戶可以承擔不同的角色,從而實現授權的靈活性。當然,Group也可以實現類似的功能。但實際業務中,Group劃分多以行政組織結構或業務功能劃分;如果為了權限管理強行將一個用戶加入不同的組,會導致管理的復雜性。 ?
? Domain的應用。為了授權更靈活,可以將Where或者Scope抽象出來,稱之為Domain,真正的授權是在Domain的范圍內進行,具體的Resource將分屬于不同的Domain。比如:一個新聞機構有國內與國外兩大分支,兩大分支內又都有不同的資源(體育類、生活類、時事政治類)。假如所有國內新聞的權限規則都是一樣的,所有國外新聞的權限規則也相同。則可以建立兩個域,分別授權,然后只要將各類新聞與不同的域關聯,受域上的權限控制,從而使之簡化。 ?
? 權限系統還應該考慮將功能性的授權與資源性的授權分開。很多系統都只有對系統中的數據(資源)的維護有權限控制,但沒有對系統功能的權限控制。 ?
? 權限系統最好是可以分層管理而不是集中管理。大多客戶希望不同的部門能且僅能管理其部門內部的事務,而不是什么都需要一個集中的Administrator或Administrators組來管理。雖然你可以將不同部門的人都加入Administrators組,但他們的權限過大,可以管理整個系統資源而不是該部門資源。 ?
? 正向授權與負向授權:正向授權在開始時假定主體沒有任何權限,然后根據需要授予權限,適合于權限要求嚴格的系統。負向授權在開始時假定主體有所有權限,然后將某些特殊權限收回。 ?
? 權限計算策略:系統中User,Group,Role都可以授權,權限可以有正負向之分,在計算用戶的凈權限時定義一套策略。 ?
? 系統中應該有一個集中管理權限的AccessService,負責權限的維護(業務管理員、安全管理模塊)與使用(最終用戶、各功能模塊),該AccessService在實現時要同時考慮一般權限與特殊權限。雖然在具體實現上可以有很多,比如用Proxy模式,但應該使這些Proxy依賴于AccessService。各模塊功能中調用AccessService來檢查是否有相應的權限。所以說,權限管理不是安全管理模塊自己一個人的事情,而是與系統各功能模塊都有關系。每個功能模塊的開發人員都應該熟悉安全管理模塊,當然,也要從業務上熟悉本模塊的安全規則。 ?
? 技術實現: ?
? 1.表單式認證,這是常用的,但用戶到達一個不被授權訪問的資源時,Web容器就發 ?
? 出一個html頁面,要求輸入用戶名和密碼。 ? ?
? 2.一個基于Servlet ? Sign ? in/Sign ? out來集中處理所有的Request,缺點是必須由應用程序自己來處理。 ?
? 3.用Filter防止用戶訪問一些未被授權的資源,Filter會截取所有Request/Response, ?
? 然后放置一個驗證通過的標識在用戶的Session中,然后Filter每次依靠這個標識來決定是否放行Response。 ?
? 這個模式分為: ?
? Gatekeeper ? :采取Filter或統一Servlet的方式。 ?
? Authenticator: ? 在Web中使用JAAS自己來實現。 ?
? 用戶資格存儲LDAP或數據庫: ?
? 1. ? Gatekeeper攔截檢查每個到達受保護的資源。首先檢查這個用戶是否有已經創建 ?
? 好的Login ? Session,如果沒有,Gatekeeper ? 檢查是否有一個全局的和Authenticator相關的session? ?
? 2. ? 如果沒有全局的session,這個用戶被導向到Authenticator的Sign-on ? 頁面, ?
? 要求提供用戶名和密碼。 ?
? 3. ? Authenticator接受用戶名和密碼,通過用戶的資格系統驗證用戶。 ?
? 4. ? 如果驗證成功,Authenticator將創建一個全局Login ? session,并且導向Gatekeeper ?
? 來為這個用戶在他的web應用中創建一個Login ? Session。 ?
? 5. ? Authenticator和Gatekeepers聯合分享Cookie,或者使用Tokens在Query字符里。
但凡涉及多用戶不同權限的網絡或者單機程序,都會有權限管理的問題,比較突出的是MIS系統。 ? ?
? ?
? 下面我要說的是MIS系統權限管理的數據庫設計及實現,當然,這些思路也可以推廣開來應用,比如說在BBS中用來管理不同級別的用戶權限。 ? ?
? ?
? 權限設計通常包括數據庫設計、應用程序接口(API)設計、程序實現三個部分。 ? ?
? ?
? 這三個部分相互依存,密不可分,要實現完善的權限管理體系,必須考慮到每一個環節可行性與復雜程度甚至執行效率。 ? ?
? ?
? 我們將權限分類,首先是針對數據存取的權限,通常有錄入、瀏覽、修改、刪除四種,其次是功能,它可以包括例如統計等所有非直接數據存取操作,另外,我們還可能對一些關鍵數據表某些字段的存取進行限制。除此,我想不出還有另外種類的權限類別。 ? ?
? ?
? 完善的權限設計應該具有充分的可擴展性,也就是說,系統增加了新的其它功能不應該對整個權限管理體系帶來較大的變化,要達到這個目的,首先是數據庫設計合理,其次是應用程序接口規范。 ? ?
? ?
? 我們先討論數據庫設計。通常我們使用關系數據庫,這里不討論基于Lotus產品的權限管理。 ? ?
? ?
? 權限表及相關內容大體可以用六個表來描述,如下: ? ?
? 1 ? 角色(即用戶組)表:包括三個字段,ID,角色名,對該角色的描述; ? ?
? 2 ? 用戶表:包括三個或以上字段,ID,用戶名,對該用戶的描述,其它(如地址、電話等信息); ? ?
? 3 ? 角色-用戶對應表:該表記錄用戶與角色之間的對應關系,一個用戶可以隸屬于多個角色,一個角色組也可擁有多個用戶。包括三個字段,ID,角色ID,用戶ID; ? ?
? 4 ? 限制內容列表:該表記錄所有需要加以權限區分限制的數據表、功能和字段等內容及其描述,包括三個字段,ID,名稱,描述; ? ?
? 5 ? 權限列表:該表記錄所有要加以控制的權限,如錄入、修改、刪除、執行等,也包括三個字段,ID,名稱,描述; ? ?
? 6 ? 權限-角色-用戶對應表:一般情況下,我們對角色/用戶所擁有的權限做如下規定,角色擁有明令允許的權限,其它一律禁止,用戶繼承所屬角色的全部權限,在此范圍內的權限除明令禁止外全部允許,范圍外權限除明令允許外全部禁止。該表的設計是權限管理的重點,設計的思路也很多,可以說各有千秋,不能生搬硬套說某種方法好。對此,我的看法是就個人情況,找自己覺得合適能解決問題的用。 ? ?
? ?
? 先說第一種也是最容易理解的方法,設計五個字段:ID,限制內容ID,權限ID,角色/用戶類型(布爾型字段,用來描述一條記錄記錄的是角色權限還是用戶權限),角色/用戶ID,權限類型(布爾型字段,用來描述一條記錄表示允許還是禁止) ? ?
? ?
? 好了,有這六個表,根據表六,我們就可以知道某個角色/用戶到底擁有/禁止某種權限。 ? ?
? ?
? 或者說,這么設計已經足夠了,我們完全實現了所需要的功能:可以對角色和用戶分別進行權限定制,也具有相當的可擴展性,比如說增加了新功能,我們只需要添加一條或者幾條記錄就可以,同時應用程序接口也無須改動,具有相當的可行性。但是,在程序實現的過程中,我們發現,使用這種方法并不是十分科學,例如瀏覽某個用戶所擁有的權限時,需要對數據庫進行多次(甚至是遞歸)查詢,極不方便。于是我們需要想其它的辦法。使用過Unix系統的人們都知道,Unix文件系統將對文件的操作權限分為三種:讀、寫和執行,分別用1、2、4三個代碼標識,對用戶同時具有讀寫權限的文件被記錄為3,即1+2。我們也可以用類似的辦法來解決這個問題。初步的想法是修改權限列表,加入一個字段:標識碼,例如,我們可以將錄入權限標識為1,瀏覽權限標識為2,修改權限標識為4,刪除權限標識為8,執行權限標識為16,這樣,我們通過權限累加的辦法就可以輕易的將原本要分為幾條記錄描述的權限放在一起了,例如,假定某用戶ID為1,庫存表對應的限制內容ID為2,同時規定角色類型為0、用戶類型為1,我們就可以將該用戶具有錄入、瀏覽、修改、刪除庫存表的權限描述為:2,15,1,1。 ? ?
? ?
? 確實很簡單,不是嗎?甚至還有更過激的辦法,將限制內容列表也加上一列,定義好標識碼,這樣,我們甚至可以用簡單的一條記錄描述某個用戶具有的對全部內容所具有的全部權限了。當然,這樣做的前提是限制內容數量比較小,不然,呵呵,2的n次方遞增起來可是數量驚人,不容易解析的。 ? ?
? ?
? 從表面上看,上述方法足以達到實現功能、簡化數據庫設計及實現的復雜度這個目的,但這樣做有個弊端,我們所涉及的權限列表不是相互獨立而是互相依賴的,比如說修改權限,其實是包含瀏覽權限的,例如,我們可能只是簡單的設置用戶對庫存表存取的權限值為錄入+修改+刪除(1+4+8=13),但事實上,該用戶具有(1+2+4+8=15)的權限,也就是說,在這種方案中,13=15。于是當我們調用API詢問某用戶是否具有瀏覽權限時,就必須判斷該用戶是否具有對該數據表的修改權限,因此,如果不能在程序中固化權限之間的包含關系,就不能利用應用程序接口簡單的做出判斷。但這與我們的目的“充分的可擴展性”矛盾。 ? ?
? ?
? 這個問題如何解決?我想到了另外一種設置標識碼的方法,那就是利用素數。我們不妨將錄入、瀏覽、修改、刪除、執行的基本標志碼定為2,3,5,7,11,當遇到權限互相包含的時候,我們將它的標識碼設定為兩個(或多個)基本標志碼的乘積,例如,可以將“修改”功能的標志碼定為3*5=15,然后將所有的權限相乘,就得到了我們需要的最終權限標識值。這樣,我們在詢問用戶是否具有某項權限的時候,只需要將最終的值分解成質因子,例如,我們可以定義一個用戶具有錄入+修改+刪除庫存表的權限為 ? 2*15*7=2*3*5*7,即表示,該用戶具有了對庫存表錄入+瀏覽+修改+刪除權限。 ? ?
? ?
? 當然,對權限列表我們使用上述方法的前提是權限列表記錄條數不會太多并且關系不是十分復雜,否則,光是解析權限代碼就要機器忽悠半宿:) ? ?
? ?
? 我希望以上的分析是正確且有效的(事實上,我也用這些的方法在不止一套系統中實現),但無論如何,我覺得如此實現權限管理,只是考慮了數據庫設計和應用程序接口兩部分內容,對于實現,還是顯得很費勁。因此,我懇請有過類似設計、實現經驗的同志們提出建設性的意見和修改建議。 ? ?
? ?
? 另外,關于數據庫設計的思路還有使用二維表的,這將在以后的時間里討論,關于應用程序接口的設計和實現我也將在利用另外篇幅和大家共同探討,代碼將用類C語法實現(我不喜歡pascal,抱歉)?????
????
?
? 權限往往是一個極其復雜的問題,但也可簡單表述為這樣的邏輯表達式:判斷“Who對What(Which)進行How的操作”的邏輯表達式是否為真。針對不同的
? 目標: ?
? 直觀,因為系統最終會由最終用戶來維護,權限分配的直觀和容易理解,顯得比較重要,系統不辭勞苦的實現了組的繼承,除了功能的必須,更主要的就是因為它足夠直觀。 ?
? 簡單,包括概念數量上的簡單和意義上的簡單還有功能上的簡單。想用一個權限系統解決所有的權限問題是不現實的。設計中將常常變化的“定制”特點比較強的部分判斷為業務邏輯,而將常常相同的“通用”特點比較強的部分判斷為權限邏輯就是基于這樣的思路。 ?
? 擴展,采用可繼承在擴展上的困難。的Group概念在支持權限以組方式定義的同時有效避免了重定義時 ?
? 現狀: ?
? 對于在企業環境中的訪問控制
? 1.自主型訪問控制方法。目前在我國的大多數的信息系統中的訪問控制模塊中基本是借助于自主型訪問控制方法中的訪問控制列表(ACLs)。 ?
? 2.強制型訪問控制方法。用于多層次安全級別的
? 3.基于角色的訪問控制方法(RBAC)。是目前公認的解決大型企業的統一資源訪問控制的有效方法。其顯著的兩大特征是:1.減小授權管理的復雜性,降低管理開銷。2.靈活地支持企業的安全策略,并對企業的變化有很大的伸縮性。 ?
? 名詞: ?
? 粗粒度:表示類別級,即僅考慮對象的類別(the ? type ? of ? object),不考慮對象的某個特 ?
? 定實例。比如,用戶管理中,創建、刪除,對所有的用戶都一視同仁,并不區分操作的具體對象實例。 ?
? 細粒度:表示實例級,即需要考慮具體對象的實例(the ? instance ? of ? object),當然,細 ?
? 粒度是在考慮粗粒度的對象類別之后才再考慮特定實例。比如,合同管理中,列表、刪除,需要區分該合同實例是否為當前用戶所創建。 ?
? 原則: ?
? 權限邏輯配合業務邏輯。即權限系統以為業務邏輯提供服務為目標。相當多細粒度的權限問題因其極其獨特而不具通用意義,它們也能被理解為是“業務邏輯”的一部分。比如,要求:“合同資源只能被它的創建者刪除,與創建者同組的用戶可以修改,所有的用戶能夠瀏覽”。這既可以認為是一個細粒度的權限問題,也可以認為是一個業務邏輯問題。在這里它是業務邏輯問題,在整個權限系統的架構設計之中不予過多考慮。當然,權限系統的架構也必須要能支持這樣的控制判斷。或者說,系統提供足夠多但不是完全的控制
? 需要再次強調的是,這里表述的權限系統僅是一個“不完全”的權限系統,即,它不提供所有關于權限的問題的解決方法。它提供一個基礎,并解決那些具有“共性”的(或者說粗粒度的)部分。在這個基礎之上,根據“業務邏輯”的獨特權限需求,編碼實現剩余部分(或者說細粒度的)部分,才算完整?;氐綑嘞薜膯栴}公式,通用的設計僅解決了Who+What+How ? 的問題,其他的權限問題留給業務邏輯解決。 ?
? 概念: ?
? Who:權限的擁用者或主體(Principal、User、Group、Role、Actor等等) ?
? What:權限針對的對象或資源(Resource、Class)。 ?
? How:具體的權限(Privilege, ? 正向授權與負向授權)。 ?
? Role:是角色,擁有一定數量的權限。 ?
? Operator:操作。表明對What的How ? 操作。 ?
? 說明: ?
? User:與 ? Role ? 相關,用戶僅僅是純粹的用戶,權限是被分離出去了的。User是不能與 ? Privilege ? 直接相關的,User ? 要擁有對某種資源的權限,必須通過Role去關聯。解決 ? Who ? 的問題。 ?
? Resource:就是系統的資源,比如部門新聞,文檔等各種可以被提供給用戶訪問的對象。資源可以反向包含自身,即樹狀結構,每一個資源節點可以與若干指定權限類別相關可定義是否將其權限應用于子節點。 ?
? Privilege:是Resource ? Related的權限。就是指,這個權限是綁定在特定的資源實例上的。比如說部門新聞的發布權限,叫做"部門新聞發布權限"。這就表明,該Privilege是一個發布權限,而且是針對部門新聞這種資源的一種發布權限。Privilege是由Creator在做開發時就確定的。權限,包括系統定義權限和用戶自定義權限用戶自定義權限之間可以指定排斥和包含關系(如:讀取,修改,管理三個權限,管理 ? 權限 ? 包含 ? 前兩種權限)。Privilege ? 如"刪除" ? 是一個抽象的名詞,當它不與任何具體的 ? Object ? 或 ? Resource ? 綁定在一起時是沒有任何意義的。拿新聞發布來說,發布是一種權限,但是只說發布它是毫無意義的。因為不知道發布可以操作的對象是什么。只有當發布與新聞結合在一起時,才會產生真正的 ? Privilege。這就是 ? Privilege ? Instance。權限系統根據需求的不同可以延伸生很多不同的版本。 ?
? Role:是粗粒度和細粒度(業務邏輯)的接口,一個基于粗粒度控制的權限框架軟件,對外的接口應該是Role,具體業務實現可以直接繼承或拓展豐富Role的內容,Role不是如同User或Group的具體實體,它是接口概念,抽象的通稱。 ?
? Group:用戶組,權限分配的單位與載體。權限不考慮分配給特定的用戶。組可以包括組(以實現權限的繼承)。組可以包含用戶,組內用戶繼承組的權限。Group要實現繼承。即在創建時必須要指定該Group的Parent是什么Group。在粗粒度控制上,可以認為,只要某用戶直接或者間接的屬于某個Group那么它就具備這個Group的所有操作許可。細粒度控制上,在業務邏輯的判斷中,User僅應關注其直接屬于的Group,用來判斷是否“同組” ? 。Group是可繼承的,對于一個分級的權限實現,某個Group通過“繼承”就已經直接獲得了其父Group所擁有的所有“權限集合”,對這個Group而言,需要與權限建立直接關聯的,僅是它比起其父Group需要“擴展”的那部分權限。子組繼承父組的所有權限,規則來得更簡單,同時意味著管理更容易。為了更進一步實現權限的繼承,最直接的就是在Group上引入“父子關系”。 ?
? User與Group是多對多的關系。即一個User可以屬于多個Group之中,一個Group可以包括多個User。子Group與父Group是多對一的關系。Operator某種意義上類似于Resource ? + ? Privilege概念,但這里的Resource僅包括Resource ? Type不表示Resource ? Instance。Group ? 可以直接映射組織結構,Role ? 可以直接映射組織結構中的業務角色,比較直觀,而且也足夠靈活。Role對系統的貢獻實質上就是提供了一個比較粗顆粒的分配單位。 ?
? Group與Operator是多對多的關系。各概念的關系圖示如下: ?
? 解釋: ?
? Operator的定義包括了Resource ? Type和Method概念。即,What和How的概念。之所以將What和How綁定在一起作為一個Operator概念而不是分開建模再建立關聯,這是因為很多的How對于某What才有意義。比如,發布操作對新聞對象才有意義,對用戶對象則沒有意義。 ?
? How本身的意義也有所不同,具體來說,對于每一個What可以定義N種操作。比如,對于合同這類對象,可以定義創建操作、提交操作、檢查沖突操作等??梢哉J為,How概念對應于每一個商業方法。其中,與具體用戶身份相關的操作既可以定義在操作的業務邏輯之中,也可以定義在操作級別。比如,創建者的瀏覽視圖與普通用戶的瀏覽視圖要求內容不同。既可以在外部定義兩個操作方法,也可以在一個操作方法的內部根據具體邏輯進行處理。具體應用哪一種方式應依據實際情況進行處理。
?
這樣的架構,應能在易于理解和管理的情況下,滿足絕大部分粗粒度權限控制的功能需要。但是除了粗粒度權限,系統中必然還會包括無數對具體Instance的細粒度權限。這些問題,被留給業務邏輯來解決,這樣的考慮基于以下兩點: ?
? 一方面,細粒度的權限判斷必須要在資源上建模權限分配的支持信息才可能得以實現。比如,如果要求創建者和普通用戶看到不同的信息內容,那么,資源本身應該有其創建者的信息。另一方面,細粒度的權限常常具有相當大的業務邏輯相關性。對不同的業務邏輯,常常意味著完全不同的權限判定原則和策略。相比之下,粗粒度的權限更具通用性,將其實現為一個架構,更有重用價值;而將細粒度的權限判斷實現為一個架構級別的東西就顯得繁瑣,而且不是那么的有必要,用定制的代碼來實現就更簡潔,更靈活。 ?
? 所以細粒度控制應該在底層解決,Resource在實例化的時候,必需指定Owner和GroupPrivilege在對Resource進行操作時也必然會確定約束類型:究竟是OwnerOK還是GroupOK還是AllOK。Group應和Role嚴格分離User和Group是多對多的關系,Group只用于對用戶分類,不包含任何Role的意義;Role只授予User,而不是Group。如果用戶需要還沒有的多種Privilege的組合,必須新增Role。Privilege必須能夠訪問Resource,同時帶User參數,這樣權限控制就完備了。 ?
? 思想: ?
? 權限系統的核心由以下三部分構成:1.創造權限,2.分配權限,3.使用權限,然后,系統各部分的主要參與者對照如下:1.創造權限 ? - ? Creator創造,2.分配權限 ? - ? Administrator ? 分配,3.使用權限 ? - ? User: ?
? 1. ? Creator ? 創造 ? Privilege, ? Creator ? 在設計和實現系統時會劃分,一個子系統或稱為模塊,應該有哪些權限。這里完成的是 ? Privilege ? 與 ? Resource ? 的對象聲明,并沒有真正將 ? Privilege ? 與具體Resource ? 實例聯系在一起,形成Operator。 ?
? 2. ? Administrator ? 指定 ? Privilege ? 與 ? Resource ? Instance ? 的關聯。在這一步, ? 權限真正與資源實例聯系到了一起, ? 產生了Operator(Privilege ? Instance)。Administrator利用Operator這個基本元素,來創造他理想中的權限模型。如,創建角色,創建用戶組,給用戶組分配用戶,將用戶組與角色關聯等等...這些操作都是由 ? Administrator ? 來完成的。 ?
? 3. ? User ? 使用 ? Administrator ? 分配給的權限去使用各個子系統。Administrator ? 是用戶,在他的心目中有一個比較適合他管理和維護的權限模型。于是,程序員只要回答一個問題,就是什么權限可以訪問什么資源,也就是前面說的 ? Operator。程序員提供 ? Operator ? 就意味著給系統穿上了盔甲。Administrator ? 就可以按照他的意愿來建立他所希望的權限框架可以自行增加,刪除,管理Resource和Privilege之間關系??梢宰孕性O定用戶User和角色Role的對應關系。(如果將 ? Creator看作是 ? Basic ? 的發明者, ? Administrator ? 就是 ? Basic ? 的使用者,他可以做一些腳本式的編程) ? Operator是這個系統中最關鍵的部分,它是一個紐帶,一個系在Programmer,Administrator,User之間的紐帶。 ?
? 用一個功能模塊來舉例子。 ?
? 一.建立角色功能并做分配: ?
? 1.如果現在要做一個員工管理的模塊(即Resources),這個模塊有三個功能,分別是:增加,修改,刪除。給這三個功能各自分配一個ID,這個ID叫做功能代號: ?
? Emp_addEmp,Emp_deleteEmp,Emp_updateEmp。 ?
? 2.建立一個角色(Role),把上面的功能代碼加到這個角色擁有的權限中,并保存到數據庫中。角色包括系統管理員,測試人員等。 ?
? 3.建立一個員工的賬號,并把一種或幾種角色賦給這個員工。比如說這個員工既可以是公司管理人員,也可以是測試人員等。這樣他登錄到系統中將會只看到他擁有權限的那些模塊。 ?
? 二.把身份信息加到Session中。 ?
? 登錄時,先到數據庫中查找是否存在這個員工,如果存在,再根據員工的sn查找員工的權限信息,把員工所有的權限信息都入到一個Hashmap中,比如就把上面的Emp_addEmp等放到這個Hashmap中。然后把Hashmap保存在一個UserInfoBean中。最后把這個UserInfoBean放到Session中,這樣在整個程序的運行過程中,系統隨時都可以取得這個用戶的身份信息。 ?
? 三.根據用戶的權限做出不同的顯示。 ?
? 可以對比當前員工的權限和給這個菜單分配的“功能ID”判斷當前用戶是否有打開這個菜單的權限。例如:如果保存員工權限的Hashmap中沒有這三個ID的任何一個,那這個菜單就不會顯示,如果員工的Hashmap中有任何一個ID,那這個菜單都會顯示。 ? ?
? 對于一個新聞系統(Resouce),假設它有這樣的功能(Privilege):查看,發布,刪除,修改;假設對于刪除,有"新聞系統管理者只能刪除一月前發布的,而超級管理員可刪除所有的這樣的限制,這屬于業務邏輯(Business ? logic),而不屬于用戶權限范圍。也就是說權限負責有沒有刪除的Permission,至于能刪除哪些內容應該根據UserRole ? or ? UserGroup來決定(當然給UserRole ? or ? UserGroup分配權限時就應該包含上面兩條業務邏輯)。 ?
? 一個用戶可以擁有多種角色,但同一時刻用戶只能用一種角色進入系統。角色的劃分方法可以根據實際情況劃分,按部門或機構進行劃分的,至于角色擁有多少權限,這就看系統管理員賦給他多少的權限了。用戶—角色—權限的關鍵是角色。用戶登錄時是以用戶和角色兩種屬性進行登錄的(因為一個用戶可以擁有多種角色,但同一時刻只能扮演一種角色),根據角色得到用戶的權限,登錄后進行初始化。這其中的技巧是同一時刻某一用戶只能用一種角色進行登錄。 ?
? 針對不同的“角色”動態的建立不同的組,每個項目建立一個單獨的Group,對于新的項目,建立新的 ? Group ? 即可。在權限判斷部分,應在商業方法上予以控制。比如:不同用戶的“操作能力”是不同的(粗粒度的控制應能滿足要求),不同用戶的“可視區域”是不同的(體現在對被操作的對象的權限數據,是否允許當前用戶訪問,這需要對業務數據建模的時候考慮權限控制需要)。???
?
擴展性: ?
? 有了用戶/權限管理的基本框架,Who(User/Group)的概念是不會經常需要擴展的。變化的可能是系統中引入新的 ? What ? (新的Resource類型)或者新的How(新的操作方式)。那在三個基本概念中,僅在Permission上進行擴展是不夠的。這樣的設計中Permission實質上解決了How ? 的問題,即表示了“怎樣”的操作。那么這個“怎樣”是在哪一個層次上的定義呢?將Permission定義在“商業方法”級別比較合適。比如,發布、購買、取消。每一個商業方法可以意味著用戶進行的一個“動作”。定義在商業邏輯的層次上,一方面保證了數據訪問代碼的“純潔性”,另一方面在功能上也是“足夠”的。也就是說,對更低層次,能自由的訪問數據,對更高層次,也能比較精細的控制權限。 ?
? 確定了Permission定義的合適層次,更進一步,能夠發現Permission實際上還隱含了What的概念。也就是說,對于What的How操作才會是一個完整的Operator。比如,“發布”操作,隱含了“信息”的“發布”概念,而對于“商品”而言發布操作是沒有意義的。同樣的,“購買”操作,隱含了“商品”的“購買”概念。這里的綁定還體現在大量通用的同名的操作上,比如,需要區分“商品的刪除”與“信息的刪除”這兩個同名為“刪除”的不同操作。 ?
? 提供權限系統的擴展能力是在Operator ? (Resource ? + ? Permission)的概念上進行擴展。Proxy ? 模式是一個非常合適的實現方式。實現大致如下:在業務邏輯層(EJB ? Session ? Facade ? [Stateful ? SessionBean]中),取得該商業方法的Methodname,再根據Classname和 ? Methodname ? 檢索Operator ? 數據,然后依據這個Operator信息和Stateful中保存的User信息判斷當前用戶是否具備該方法的操作權限。 ?
? 應用在 ? EJB ? 模式下,可以定義一個很明確的 ? Business層次,而一個Business ? 可能意味著不同的視圖,當多個視圖都對應于一個業務邏輯的時候,比如,Swing ? Client以及 ? Jsp ? Client ? 訪問的是同一個 ? EJB ? 實現的 ? Business。在 ? Business ? 層上應用權限較能提供集中的控制能力。實際上,如果權限系統提供了查詢能力,那么會發現,在視圖層次已經可以不去理解權限,它只需要根據查詢結果控制界面就可以了。 ?
? 靈活性: ?
? Group和Role,只是一種輔助實現的手段,不是必需的。如果系統的Role很多,逐個授權違背了“簡單,方便”的目的,那就引入Group,將權限相同的Role組成一個Group進行集中授權。Role也一樣,是某一類Operator的集合,是為了簡化針對多個Operator的操作。 ?
? Role把具體的用戶和組從權限中解放出來。一個用戶可以承擔不同的角色,從而實現授權的靈活性。當然,Group也可以實現類似的功能。但實際業務中,Group劃分多以行政組織結構或業務功能劃分;如果為了權限管理強行將一個用戶加入不同的組,會導致管理的復雜性。 ?
? Domain的應用。為了授權更靈活,可以將Where或者Scope抽象出來,稱之為Domain,真正的授權是在Domain的范圍內進行,具體的Resource將分屬于不同的Domain。比如:一個新聞機構有國內與國外兩大分支,兩大分支內又都有不同的資源(體育類、生活類、時事政治類)。假如所有國內新聞的權限規則都是一樣的,所有國外新聞的權限規則也相同。則可以建立兩個域,分別授權,然后只要將各類新聞與不同的域關聯,受域上的權限控制,從而使之簡化。 ?
? 權限系統還應該考慮將功能性的授權與資源性的授權分開。很多系統都只有對系統中的數據(資源)的維護有權限控制,但沒有對系統功能的權限控制。 ?
? 權限系統最好是可以分層管理而不是集中管理。大多客戶希望不同的部門能且僅能管理其部門內部的事務,而不是什么都需要一個集中的Administrator或Administrators組來管理。雖然你可以將不同部門的人都加入Administrators組,但他們的權限過大,可以管理整個系統資源而不是該部門資源。 ?
? 正向授權與負向授權:正向授權在開始時假定主體沒有任何權限,然后根據需要授予權限,適合于權限要求嚴格的系統。負向授權在開始時假定主體有所有權限,然后將某些特殊權限收回。 ?
? 權限計算策略:系統中User,Group,Role都可以授權,權限可以有正負向之分,在計算用戶的凈權限時定義一套策略。 ?
? 系統中應該有一個集中管理權限的AccessService,負責權限的維護(業務管理員、安全管理模塊)與使用(最終用戶、各功能模塊),該AccessService在實現時要同時考慮一般權限與特殊權限。雖然在具體實現上可以有很多,比如用Proxy模式,但應該使這些Proxy依賴于AccessService。各模塊功能中調用AccessService來檢查是否有相應的權限。所以說,權限管理不是安全管理模塊自己一個人的事情,而是與系統各功能模塊都有關系。每個功能模塊的開發人員都應該熟悉安全管理模塊,當然,也要從業務上熟悉本模塊的安全規則。 ?
? 技術實現: ?
? 1.表單式認證,這是常用的,但用戶到達一個不被授權訪問的資源時,Web容器就發 ?
? 出一個html頁面,要求輸入用戶名和密碼。 ? ?
? 2.一個基于Servlet ? Sign ? in/Sign ? out來集中處理所有的Request,缺點是必須由應用程序自己來處理。 ?
? 3.用Filter防止用戶訪問一些未被授權的資源,Filter會截取所有Request/Response, ?
? 然后放置一個驗證通過的標識在用戶的Session中,然后Filter每次依靠這個標識來決定是否放行Response。 ?
? 這個模式分為: ?
? Gatekeeper ? :采取Filter或統一Servlet的方式。 ?
? Authenticator: ? 在Web中使用JAAS自己來實現。 ?
? 用戶資格存儲LDAP或數據庫: ?
? 1. ? Gatekeeper攔截檢查每個到達受保護的資源。首先檢查這個用戶是否有已經創建 ?
? 好的Login ? Session,如果沒有,Gatekeeper ? 檢查是否有一個全局的和Authenticator相關的session? ?
? 2. ? 如果沒有全局的session,這個用戶被導向到Authenticator的Sign-on ? 頁面, ?
? 要求提供用戶名和密碼。 ?
? 3. ? Authenticator接受用戶名和密碼,通過用戶的資格系統驗證用戶。 ?
? 4. ? 如果驗證成功,Authenticator將創建一個全局Login ? session,并且導向Gatekeeper ?
? 來為這個用戶在他的web應用中創建一個Login ? Session。 ?
? 5. ? Authenticator和Gatekeepers聯合分享Cookie,或者使用Tokens在Query字符里。
但凡涉及多用戶不同權限的網絡或者單機程序,都會有權限管理的問題,比較突出的是MIS系統。 ? ?
? ?
? 下面我要說的是MIS系統權限管理的數據庫設計及實現,當然,這些思路也可以推廣開來應用,比如說在BBS中用來管理不同級別的用戶權限。 ? ?
? ?
? 權限設計通常包括數據庫設計、應用程序接口(API)設計、程序實現三個部分。 ? ?
? ?
? 這三個部分相互依存,密不可分,要實現完善的權限管理體系,必須考慮到每一個環節可行性與復雜程度甚至執行效率。 ? ?
? ?
? 我們將權限分類,首先是針對數據存取的權限,通常有錄入、瀏覽、修改、刪除四種,其次是功能,它可以包括例如統計等所有非直接數據存取操作,另外,我們還可能對一些關鍵數據表某些字段的存取進行限制。除此,我想不出還有另外種類的權限類別。 ? ?
? ?
? 完善的權限設計應該具有充分的可擴展性,也就是說,系統增加了新的其它功能不應該對整個權限管理體系帶來較大的變化,要達到這個目的,首先是數據庫設計合理,其次是應用程序接口規范。 ? ?
? ?
? 我們先討論數據庫設計。通常我們使用關系數據庫,這里不討論基于Lotus產品的權限管理。 ? ?
? ?
? 權限表及相關內容大體可以用六個表來描述,如下: ? ?
? 1 ? 角色(即用戶組)表:包括三個字段,ID,角色名,對該角色的描述; ? ?
? 2 ? 用戶表:包括三個或以上字段,ID,用戶名,對該用戶的描述,其它(如地址、電話等信息); ? ?
? 3 ? 角色-用戶對應表:該表記錄用戶與角色之間的對應關系,一個用戶可以隸屬于多個角色,一個角色組也可擁有多個用戶。包括三個字段,ID,角色ID,用戶ID; ? ?
? 4 ? 限制內容列表:該表記錄所有需要加以權限區分限制的數據表、功能和字段等內容及其描述,包括三個字段,ID,名稱,描述; ? ?
? 5 ? 權限列表:該表記錄所有要加以控制的權限,如錄入、修改、刪除、執行等,也包括三個字段,ID,名稱,描述; ? ?
? 6 ? 權限-角色-用戶對應表:一般情況下,我們對角色/用戶所擁有的權限做如下規定,角色擁有明令允許的權限,其它一律禁止,用戶繼承所屬角色的全部權限,在此范圍內的權限除明令禁止外全部允許,范圍外權限除明令允許外全部禁止。該表的設計是權限管理的重點,設計的思路也很多,可以說各有千秋,不能生搬硬套說某種方法好。對此,我的看法是就個人情況,找自己覺得合適能解決問題的用。 ? ?
? ?
? 先說第一種也是最容易理解的方法,設計五個字段:ID,限制內容ID,權限ID,角色/用戶類型(布爾型字段,用來描述一條記錄記錄的是角色權限還是用戶權限),角色/用戶ID,權限類型(布爾型字段,用來描述一條記錄表示允許還是禁止) ? ?
? ?
? 好了,有這六個表,根據表六,我們就可以知道某個角色/用戶到底擁有/禁止某種權限。 ? ?
? ?
? 或者說,這么設計已經足夠了,我們完全實現了所需要的功能:可以對角色和用戶分別進行權限定制,也具有相當的可擴展性,比如說增加了新功能,我們只需要添加一條或者幾條記錄就可以,同時應用程序接口也無須改動,具有相當的可行性。但是,在程序實現的過程中,我們發現,使用這種方法并不是十分科學,例如瀏覽某個用戶所擁有的權限時,需要對數據庫進行多次(甚至是遞歸)查詢,極不方便。于是我們需要想其它的辦法。使用過Unix系統的人們都知道,Unix文件系統將對文件的操作權限分為三種:讀、寫和執行,分別用1、2、4三個代碼標識,對用戶同時具有讀寫權限的文件被記錄為3,即1+2。我們也可以用類似的辦法來解決這個問題。初步的想法是修改權限列表,加入一個字段:標識碼,例如,我們可以將錄入權限標識為1,瀏覽權限標識為2,修改權限標識為4,刪除權限標識為8,執行權限標識為16,這樣,我們通過權限累加的辦法就可以輕易的將原本要分為幾條記錄描述的權限放在一起了,例如,假定某用戶ID為1,庫存表對應的限制內容ID為2,同時規定角色類型為0、用戶類型為1,我們就可以將該用戶具有錄入、瀏覽、修改、刪除庫存表的權限描述為:2,15,1,1。 ? ?
? ?
? 確實很簡單,不是嗎?甚至還有更過激的辦法,將限制內容列表也加上一列,定義好標識碼,這樣,我們甚至可以用簡單的一條記錄描述某個用戶具有的對全部內容所具有的全部權限了。當然,這樣做的前提是限制內容數量比較小,不然,呵呵,2的n次方遞增起來可是數量驚人,不容易解析的。 ? ?
? ?
? 從表面上看,上述方法足以達到實現功能、簡化數據庫設計及實現的復雜度這個目的,但這樣做有個弊端,我們所涉及的權限列表不是相互獨立而是互相依賴的,比如說修改權限,其實是包含瀏覽權限的,例如,我們可能只是簡單的設置用戶對庫存表存取的權限值為錄入+修改+刪除(1+4+8=13),但事實上,該用戶具有(1+2+4+8=15)的權限,也就是說,在這種方案中,13=15。于是當我們調用API詢問某用戶是否具有瀏覽權限時,就必須判斷該用戶是否具有對該數據表的修改權限,因此,如果不能在程序中固化權限之間的包含關系,就不能利用應用程序接口簡單的做出判斷。但這與我們的目的“充分的可擴展性”矛盾。 ? ?
? ?
? 這個問題如何解決?我想到了另外一種設置標識碼的方法,那就是利用素數。我們不妨將錄入、瀏覽、修改、刪除、執行的基本標志碼定為2,3,5,7,11,當遇到權限互相包含的時候,我們將它的標識碼設定為兩個(或多個)基本標志碼的乘積,例如,可以將“修改”功能的標志碼定為3*5=15,然后將所有的權限相乘,就得到了我們需要的最終權限標識值。這樣,我們在詢問用戶是否具有某項權限的時候,只需要將最終的值分解成質因子,例如,我們可以定義一個用戶具有錄入+修改+刪除庫存表的權限為 ? 2*15*7=2*3*5*7,即表示,該用戶具有了對庫存表錄入+瀏覽+修改+刪除權限。 ? ?
? ?
? 當然,對權限列表我們使用上述方法的前提是權限列表記錄條數不會太多并且關系不是十分復雜,否則,光是解析權限代碼就要機器忽悠半宿:) ? ?
? ?
? 我希望以上的分析是正確且有效的(事實上,我也用這些的方法在不止一套系統中實現),但無論如何,我覺得如此實現權限管理,只是考慮了數據庫設計和應用程序接口兩部分內容,對于實現,還是顯得很費勁。因此,我懇請有過類似設計、實現經驗的同志們提出建設性的意見和修改建議。 ? ?
? ?
? 另外,關于數據庫設計的思路還有使用二維表的,這將在以后的時間里討論,關于應用程序接口的設計和實現我也將在利用另外篇幅和大家共同探討,代碼將用類C語法實現(我不喜歡pascal,抱歉)?????
????
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
