在
Jive
中除了前面介紹的有關設計模式實現組件外,還有其他有一定特點的組件功能,分析研究這些組件功能可以更加完整透徹地理解
Jive
論壇系統。
Jive
安全管理機制基本是由下列部分組成:
·?????????
安全驗證機制。主要是驗證用戶名和密碼組合是否與數據庫中注冊時的數據一致,以確認該用戶身份為注冊用戶。這是對所有的
JSP
訪問都進行攔截訪問。
·?????????
訪問權限控制(
ACL
)。對不同的數據不同用戶擁有不同的訪問權限,例如,一個帖子普通用戶可以瀏覽,但是不能更該;但是管理員卻可以編輯刪除。這部分功能是通過代理模式實現,為每個關鍵數據都建立一個代理類用來實現訪問權限檢查,這在前面討論過。
·?????????
用戶資料管理系統。主要是管理用戶的資料數據,進行用戶組和用戶關系的建立等。
1?
安全驗證機制
Jive
的安全驗證機制是按照比較通用的思路設計的。類似前面“簡單的用戶注冊管理系統”中的介紹,
Jive
也是在所有的
JSP
頁面中
include
一個安全檢驗功能的
global.jsp
。由于
global.jsp
是在每個
JSP
一開始必須執行的功能,因此通過攔截
global.jsp
攔截發往各個
JSP
頁面的請求(
request
)。如果這個請求是合法的,將被允許通過;如果不是,將注明請求者身份是
Anonymous
(匿名者)。
global.jsp
代碼如下:
boolean isGuest = false;
Authorization authToken = SkinUtils.getUserAuthorization(request, response);
if (authToken == null) {//
未被驗證通過
??? authToken = AuthorizationFactory.getAnonymousAuthorization();
??? isGuest=true;
}
在
Jive
中,以
Authorization
對象作為驗證通過的標志,它的接口代碼如下:
public interface Authorization {
??? public long getUserID();???
??? public boolean isAnonymous();
}
具體實現是
DbAuthorization
,代碼如下:
public final class DbAuthorization implements Authorization, Serializable {
??? private long userID;
??? protected DbAuthorization(long userID) {
??????? this.userID = userID;
??? }
??? public long getUserID() {
??????? return userID;
??? }
??? public boolean isAnonymous() {
??????? return userID == -1;
??? }
}
此類只是一個
userID
,因此只是一個象征性的標志。
SkinUtils
是一個為
JSP
服務的類,它的
getUserAuthorization
代碼如下:
public static Authorization getUserAuthorization
??????? (HttpServletRequest request, HttpServletResponse response)
? {
??? HttpSession session = request.getSession();
??? //
從
HttpSession
中獲取
Authorization
實例
??? Authorization authToken =
(Authorization)session.getAttribute(JIVE_AUTH_TOKEN);
??? if (authToken != null) {???? return authToken;? }
?
??? //
如果
HttpSession
中沒有,檢查用戶瀏覽器
cookie
??? Cookie cookie = getCookie(request, JIVE_AUTOLOGIN_COOKIE);
??? if (cookie != null) {
??????? try {
?????????? String[] values = decodePasswordCookie(cookie.getValue());
?????????? String username = values[0];
?????????? String password = values[1];
?????????? //
從
cookie
中獲得用戶名和密碼后,進行安全驗證
?????????? authToken = AuthorizationFactory.getAuthorization(username,password);
??????? }catch (Exception e) {}
??????? // put that token in the user's session:
??????? if (authToken != null) {//
如果通過驗證,保存
authToken
在
http Session
?????????? session.setAttribute(JIVE_AUTH_TOKEN, authToken);
??????? }
?????? // return the authorization token
??????? return authToken;
??? }
? ??return null;
}
用戶驗證預先通過兩個步驟。首先檢查
HttpSession
中是否保存了該用戶的驗證信息,如果用戶第一次驗證通過,反復訪問,這道關口檢查就可以通過。
如果
HttpSession
中沒有驗證信息,那么從該用戶的瀏覽器
cookie
中尋找用戶名和密碼。如果該用戶激活了
cookie
保存這些登錄信息,那么應該可以找到用戶名和密碼,這樣就省卻了用戶再次從鍵盤輸入用戶名和密碼,將用戶名和密碼通過下列語句進行數據庫驗證:
authToken = AuthorizationFactory.getAuthorization(username,password);
這一舉是驗證關鍵。
AuthorizationFactory
是一個抽象類,定義了
Jive
安全驗證機制所需的所有方法,
AuthorizationFactory
的實現類似前面討論的
ForumFactory
實現,是使用工廠模式加動態類反射機制完成的,代碼如下:
public abstract class AuthorizationFactory {
?? //
定義一個數據庫具體實現
??? private static String className =
??????? " com.Yasna.forum.database.DbAuthorizationFactory";
?
??? private static AuthorizationFactory factory = null;
??? //
驗證方法
如果沒有
UnauthorizedException
拋出,表示驗證通過
??? public static Authorization getAuthorization(String username,
??????????? String password) throws UnauthorizedException
??? {
??????? loadAuthorizationFactory();
??????? return factory.createAuthorization(username, password);
??? }
??? //
匿名者處理方法
??? public static Authorization getAnonymousAuthorization() {
??????? loadAuthorizationFactory();
??????? return factory.createAnonymousAuthorization();
??? }
??? //
需要具體實現的抽象方法
??? protected abstract Authorization createAuthorization(String username,
??????????? String password) throws UnauthorizedException;
??? protected abstract Authorization createAnonymousAuthorization();
??? //
動態配置
AuthorizationFactory
的具體實現,可以在配置文件中定義一個
??? //
基于
LDAP
的實現。類似
ForumFactory
的
getInstance
方法
??? private static void loadAuthorizationFactory() {
??????? …
??? }
}
AuthorizationFactory
看上去很復雜,實際只有一個核心方法
getAuthorization
。實現用戶名和密碼的驗證。如果無法通過驗證,有兩個信息實現顯示:一個是拋出
UnauthorizedException
,另外一個是返回空的
Authorization
對象。
那么,子類
DbAuthorizationFactory
毫無疑問就是查詢數據庫,將輸入的用戶名和密碼與數據庫保存的用戶名和密碼進行校驗。
Jive
的安全驗證機制比較簡單易懂,值得在實踐中學習借鑒。但是注意到這套安全驗證機制只是
Web
層的“手工”驗證,資源訪問權限(
ACL
)也是自己“手工”來實現的。如果使用
EJB
技術,因為
EJB
容器本身有一定的資源訪問控制體系,因此在
Web
層驗證通過后,需要將這些登錄信息傳遞到
EJB
層。當然如果直接使用
Web
容器的安全驗證機制,那么
Web
層與
EJB
層之間的登錄信息傳遞將由容器實現,這樣就更加簡單方便。
Jive
這種的安全驗證并不是使用
Web
容器的安全驗證機制,如何使用
Web
容器的安全驗證機制將在以后章節介紹。盡管如此,
Jive
這套安全驗證機制對付小型系統的應用也是足夠的。
2?
用戶資料管理
在
Jive
中,用戶
User
對象的操作訪問類似于論壇
Forum
對象的訪問,與
User
對象有關的操作都封裝在一個類中操作,這是外觀(
Facade
)模式的應用。
在
Jive
中,用戶資料管理屬于大系統中的一個子系統,在這個子系統中,用戶子系統和其他系統又有一定的關系,涉及的類不少,通過建立一個
UserManager
類來統一對外接口,使得整個子系統條目結構清晰。
UserManager
中無外乎用戶數據的管理,如用戶的創建、修改、查詢和刪除。
DbUserManager
是
UserManager
的一個數據庫實現,可是看看
DbUserManager
中除了刪除功能是直接通過
SQL
語句進行數據庫刪除操作外,其他都委托給
User
的具體實現
DbUser
實現的。這種實現非常類似于
EJB
中
Session Bean
和實體
Bean
之間的關系。以創建用戶資料為例,代碼如下:
public User createUser(String username, String password, String email)
??????????? throws UserAlreadyExistsException
?{
??????? User newUser = null;
??????? try {
??????????? //
以
username
查詢改用戶是否存在
??????????? User existingUser = getUser(username);
??????????? //
如果沒有拋出
UserNotFoundException
異常,表示該用戶存在
??????????? //The user already exists since now exception, so:
??????????? throw new UserAlreadyExistsException();
??????? } catch (UserNotFoundException unfe) {
??????????? //
該用戶不存在,創建一個新用戶
??????????? newUser = new DbUser(username, password, email, factory);
??????? }
??????? return newUser;
}
DbUser
的構造方法實際是用戶資料的新增創建:
protected DbUser(String username, String password, String email,
??????????? DbForumFactory factory)
{
??????? this.id = SequenceManager.nextID(JiveGlobals.USER);? //
獲得自增
ID
??????? this.username = username;
??????? // Compute hash of password.
??? ????this.passwordHash = StringUtils.hash(password);? //
獲得加密的密碼
??????? this.email = email;
??????? this.factory = factory;
??????? long now = System.currentTimeMillis();
??????? creationDate = new java.util.Date(now);
??????? modifiedDate = new java.util.Date(now);
??????? properties = new Hashtable();
??????? insertIntoDb();????????????? //
數據庫插入數據
}
在
Jive
中,數據修改的保存是由
DbUser
的
saveToDb
方法實現的,而
saveToDb
方法調用是在每個
setXXXX
方法中。即每當外界調用
DbUser
的
setXXXX
,則表示需要改變某些字段屬性值,在這個方法中直接進行數據庫存儲,這也類似
EJB
中
CMP
實體
Bean
的數據字段修改保存。
Jive
中組
Group
與用戶
User
處理幾乎差不多,只是在
Group
中整合了權限方面的信息,這種做法是有一定的局限性,不是很值得借鑒,要想設計一個動態擴展靈活的權限系統,必須在用戶或組與權限之間引入角色概念,也就是比較先進的基于角色的權限系統(
RBAC Roled-Based Access Control
,相關網址:
http://csrc.nist.gov/rbac/
)。
在
RBAC
中,用戶組只是用戶的一個集合,應該是通過角色和權限發生聯系。所以
RBAC
認為,如果給用戶組賦予權限,那么用戶組也接近角色的概念。