用戶訪問控制(Access control )機制總是圍繞粗粒度和細粒度兩個方面來討論
粗粒度控制
可以規定訪問整個對象或對象群的某個層
而細粒度控制則總是在方法或屬性層進行控制
比如
允許一個文件為只讀是屬於粗粒度控制
而允許對這個文件某行有寫操作則屬於細粒度控制
一個好的用戶控制機制當然既允許粗粒度也允許細粒度控制
在Jive中我們看到是使用Proxy來達到這個目的
但是我們也發現
由於需要對每個類都要進行細粒度控制
所以必然對每個類都要做一個Proxy類
這樣帶來了很多Proxy類
如ForumProxy ForumThreadProxy ForumFactoryProxy等
無形增加了系統復雜性
使用動態Proxy可以很好的解決這個問題
再結合java
security
acl的ACL機制
我們就可以靈活地實現粗粒度和細粒度的雙重控制
當一個用戶login後
我們就要在內存中為其建立相應的授權訪問機制
使用java
security
acl可以很方便的建立這樣一個安全系統
首先任何一個對象都應該有個基本屬性
擁有者 或擁有者所屬組(Windows中每個目錄安全描述符都由
部分構成
對象的創建者
對象所屬的組
自由存取控制和系統存取控制)
Java acl開始第一步是建立一個主體 Principal
其中SecurityOwner是主體的擁有者
private static final Principal _securityOwner = new PrincipalImpl(
SecurityOwner
);
當用戶login進來時
他帶有兩個基本數據
訪問密碼和他要訪問的對象ApplicationName
首先驗證用戶名和密碼
然後從數據庫中取出其權限數據
建立Permission
這裡使用Feature繼承了Permission
在Feature中定義了有關權限的細節數據(如讀 寫 刪)
// 取出用戶和被訪問對象之間的權限關系
這種權限關系可能不只一個
也就是說
用戶
//可能對被訪問對象擁有讀 寫 刪等多個權限
將其打包在Hasbtable中
Hashtable features = loadFeaturesForUser(sApplicationName
sUserID);
創建一個用戶對象
User user = new UserImpl(sUserID
new Hashtable() );
為這個用戶創建一個活動的acl entry
addAclEntry( user
features);
其中最關鍵的是第四步addAclEntry
我們看看其如何實現的
// 為這個用戶創建一個新的Acl entry
AclEntry newAclEntry = new AclEntryImpl( user);
//遍歷Hashtable features
將其中多種權限加入:
feature = (Feature) hFeatures
get(keyName);
newAclEntry
addPermission( feature );
最後也要加入主體擁有者SecurityOwner
這樣一個安全體系就已經建立完成
當你在系統中要檢驗某個用戶使用擁有某個權限
如讀的權利時
只要
acl
checkPermission(user
feature )就可以
acl是ACL的一個實例
這樣權限檢查就交給
java
security
acl
ACL 去處理了
有了ACL機制後
我們就可以在我們系統中使用動態Proxy模式來對具體對象或方法進行控制
比如
我們有一個Report類
有些用戶可以讀
有些用戶可以寫(哪些用戶可以讀 哪些用戶可以寫
已經在上面ACL裡部署完成)
從Java
開始
Sun提供了Dynamic Proxy API
為了使動態Proxy能夠工作
第一你必須有一個Proxy接口
還要有一個繼承InvocationHandler的Proxy類
在下面的例子中
我們設定有三種用戶
普通人
雇員
經理
權限是這樣
普通人可以讀報告
雇員和經理可以修改報告
按通常思維
我們對於讀權限
我們設計一個具備讀的角色類
public interface IpersonRO {
public String getName();
public String getAddress();
public String getPhoneNumber();
}
類裡面都是讀的方法
這是一種粗粒度訪問控制
也就是說把讀寫權限只落實到類(對象)上
這樣的話
我們還要為寫的角色再建一個類
很顯然這不是一個很好的方法
使用動態proxy+acl就可以實現很好的細粒度控制
public class ReportProxy implements InvocationHandler
{
private Map map;
public static Object newInstance(Map map
Class[] interfaces)
{
return Proxy
newProxyInstance(map
getClass()
getClassLoader()
interfaces
new ReportProxy(map));
}
public ReportProxy(Map map)
{
this
map = map;
}
public Object invoke(Object proxy
Method m
Object[] args) throws Throwable
{
Object result;
String methodName = m
getName();
if (methodName
startsWith(
get
))
{
if (!acl
checkPermission(user
read
)) return null;
String name = methodName
substring(
methodName
indexOf(
get
)+
);
return map
get(name);
}
else if (methodName
startsWith(
set
))
{
if (!acl
checkPermission(user
write
)) return null;
String name = methodName
substring(
methodName
indexOf(
set
)+
);
map
put(name
args[
]);
return null;
}
else if (methodName
startsWith(
is
))
{
if (!acl
checkPermission(user
read
)) return null;
String name = methodName
substring(
methodName
indexOf(
is
)+
);
return(map
get(name));
}
return null;
}
}
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19404.html