在
最近對『權限管理機制』的看法 一文中提到了對權限管理機制的看法,這次則來驗證一下目前正在構思中的
權限管理 機制的理論是否可行。
原始需求
企業目前打算建立一個專案管理系統,這個系統必須針對不同的專案關係人角色而提供不同的功能操作限制,已知的情形如下:
- 每一個專案關係人會參予多個專案,並在專案管理系統中留下專案的相關文件
- 每一個專案關係人在不同的專案下會有不同的身份
- 每一個專案關係人依其身份不同而有不同的系統操作權限
功能確認
此處確認由原始需求中所捕獲到的實際所需功能
- 可以查詢某使用者可以使用的資源種類
- 可以查詢某使用者是否具備某功能的使用權
- 可以查詢某使用者在不同的資源種類下可使用的功能
前提與假設
整個機制之所以運作的必要條件(呼叫端指的是專案管理系統本身;被呼叫端指的是權限管理機制):
- 呼叫端明確知道被驗證使用者的代碼及欲檢核功能的功能名稱/代號
- 呼叫端在必要時得主動向被呼叫端進行權限驗證程序
想法
- 所謂的權限控管機制不過就是作為權限設定資料與呼叫端之間的橋樑,所以只需規範對呼叫端開放的界面格式即可。
- 為了滿足第 1 個功能,提供一個函式 public String[] getResources( String username ) 給呼叫端。
- 為了滿足第 2 個功能,提供一個函式 public Boolean hasPermission( String username, String functionID ) 給呼叫端。
- 為了滿足第 3 個功能,提供一個函式 public Boolean hasPermission( String username, String resource, String functionID ) 給呼叫端。
- 選擇傳回 Boolean 而不是 boolean 是為了做三相檢查:可、否、無。
驗證
- 如何知道專案經理 John 能否使用編號 'F004' 的功能?
檢查 hasPermission( "John", "F004" ) 的傳回值是否為 Bollean.True 後即可確認。若傳回值是 null 時則表示沒有 John 的設定,此時可以視為 John 不具有任何權限;也可解釋為 John 僅具有一般使用權限(也就是屬一般權限之使用者無需多做設定)。
- 如何知道專案經理 Micro 可以使用查看那些專案別的資料?
透過取得 getResources( "Micro" ) 傳回的字串陣列可知道 Micro 可以存取的專案代碼。例如若傳回值為 { "P0001", "P3004", "P4005" } 可視為 Micro 可以存取 P0001、P3004 以及 P4005 等三個專案的相關資訊。
- Punk 在專案 P0003 中擔任專案經理,因此得以修改 P0003 的專案相關資料。同時 Punk 在專案 P2003 中擔任顧問一職,可以調閱 P2003 的專案記錄但不能進行修改。那麼 呼叫端該如何向權限控管機制確認上述的限制呢?
- 先取得與 Punk 有關的專案代碼,取得 P0003, P2003 兩筆記錄。
String[] projects = getResources( "Punk" );
- 擷取專案記錄,例如使用 SQL 指令:
select * from ProjectInfo where projectID in ( 'P0003', 'P2003' )
- 分別檢查 Punk 對每個專案資料的修改權為何:
hasPermission( "Punk", "P0003", "MODIFY" ) == Boolean.True
hasPermission( "Punk", "P2003", "MODIFY" ) == Boolean.False
- 依所取得的權限啟用/關閉對應功能之按鈕!
權限設定記錄的保存
就 hasPermission( username, functionID ) 而言,資料的記錄很單純。
ROW | UserName | FunctionID |
---|
1 | John | F004 |
2 | Punk | MODIFY |
若是多增加一個欄位 resource 即可符合 hasPermission( username, resource, functionID ) 的需要。
ROW | UserName | Resource | FunctionID |
---|
1 | John | - | F004 |
2 | Punk | P0003 | MODIFY |
那麼要如何記錄專案關係人所屬的專案別呢?這時候加欄位並無法滿足需求,但如果考慮另外建一個結構完全一模一樣的 Table 的話呢?
ROW | UserName | Resource | FunctionID |
---|
1 | Micro | P0001 | - |
2 | Micro | P3004 | - |
3 | Micro | P4005 | - |
4 | Punk | P0003 | - |
5 | Punk | P2003 | - |
看起來似乎可行,設定上也不會很複雜(雖然可能會有點繁瑣)。換句話說只要載入兩種設定檔後即可透過交互參考而確認出某個使用者的功能及資源上的限制與否。以 OO 的方式來思考整個機制後,會有類似以下的程式碼:
{
/* 這個 code 採用類似 Java 的語法,請自行修改成所使用的語言規格 */
// 載入所屬專案表
AccessControl projectACL = new AccessControl( "ProjectInfo" );
// 載入所屬功能表
AccessControl functionACL = new AccessControl( "FunctionInfo" ); // 檢查 John 是否有 F004 的使用權
Boolean result = functionACL.hasPermission( "John", "F004" );
if ( result == null ) {
// 沒有 John 的設定值
} else if ( result.booleanValue() == true ) {
// John 可以執行 F004 的功能
} else if ( result.booleanValue() == false ) {
// John 不可以執行 F004 的功能
} // 取得 Micro 所屬的專案代碼
String[] projects = projectACL.getResources( "Micro" );
for( int i = 0; i < projects.length; i++ ) {
Logger.info( "Project Code: " + projects[i] );
} // 取得 Punk 所屬的專案代碼,且依專案別顯示可否修改內容
String[] projectsOfPunk = ProjectACL.getResources( "Punk" );
for( int j = 0; j < projectsOfPunk.length; j++ ) {
String sql = "selet * from ProjectInfo ";
sql += " where projectID = '" + projectsOfPunk[j] + "'";
ResultSet rs = sqlConnnection.execute( sql );
if( functionACL.getPermission( "Punk", projectsOfPunk[j], "MODIFY" ) == Boolean.TRUE ) {
Logger.info( "Project: " + rs.getString( "ProjectName" )
+ " is editable !" );
} else {
Logger.info( "Project: " + rs.getString( "ProjectName" )
+ " is not editable !" );
}
}
除了透過資料庫保存外,也可使用一般文字檔、XML 檔等方式保存權限設定。
更進一步
當企業內員工人數眾多,為了不把時間浪費在逐一設定使用者權限的動作上,通常會引入 ROLE 的概念。
這個簡易型權限管理機制也可以很容易的達到這項要求喔!例如有一個記錄 ROLE 使用權限的表格如下:
ROW | UserName | Resource | FunctionID |
---|
1 | ROLE_EMP | - | F001 |
2 | ROLE_EMP | - | F004 |
3 | ROLE_EMP | - | F005 |
4 | ROLE_MGR | - | ADD |
5 | ROLE_MGR | - | DELETE |
驗證動作差不多就會像這樣:
{
// 載入功能設定
AccessControl userACL = new AccessControl( "FunctionInfo" );
// 載入 Role 設定
AccessControl roleACL = new AccessControl( "RoleInfo" ); // 用戶 Jay 是 ROLE_MGR 群組
// 先檢查 Jay 有無個人權限設定
Boolean result = userACL.getPermission( "Jay", "ADD" );
if( result == null ) {
// 無個人權限設定
Boolean roleResult = roleACL.getPermission( "ROLE_MGR", "ADD" );
if( roleResult == null ) {
// 也無角色權限設定
} else {
// 有角色權限設定
}
} else {
// 有個人權限設定
}
}
結論
優點
- 不管是開發還是設定都很單純。
- 使用上很直覺。
- 彈性大,可組合多個設定表而達到對資料、對功能、對身份等的權限控管。
缺點
- 檢核過程會隨著使用到的 Table 數而愈形複雜。
- 無法簡單支援階層式權限架構,也就是上位者之權限無法延申到基層員工的權限上。
可行性
- 需要參考到超過 2 個以上的 Table 的機會應該不高。
- 操作上的複雜度取決在應用系統本身,權限管理機制本身非常單純。
- 權限設定記錄可記錄在一般商用資料庫、XML 檔、甚至 LDAP 資料庫中,應用系統無需多加考量!
- 高層主管需要管理到基層員工的記錄嗎?或許不,但卻可能需要管理到基層主管的資料。
結論
- 是否設法納入階層式權限架構呢?
- 或許可嘗試建立此函式庫。