前言
:
權限往往是一個極其復雜的問題,但也可簡單表述為這樣的邏輯表達式:判斷“
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
種操作。比如,對于合同這類對象,可以定義創建操作、提交操作、檢查沖突操作等。可以認為,
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
之間關系。可以自行設定用戶
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
字符里。