spring security3.0控制多個用戶賬號同時登錄和管理員踢出用戶(原創)

        聲明一下,這篇文章不是基於acegi  spring security2.0寫的,  我發現很多文章都是基於老版本寫的,  並不適用最新版。

下面跟大家分享一下在spring security3.0裏如何正宗的做法達到控制多個賬號請求的經驗。

 

步驟1

下面只貼出關鍵部分, 爲了不影響閱讀。

 

注意: 不需要配置 SessionRegistry 等bean( 假設你其他地方不用到的話, 如果用到需要在

<concurrency-control session-registry-ref="sessionRegistry" error-if-maximum-exceeded="true" max-sessions="1" />

加上一個屬性

 

在做某個管理員踢出一個賬號的時候, SessionRegistry 這個bean是需要用到的。 寫法如下:

 

 

有時候按文檔和網上配置出來是很華麗, 可事實有時候就是沒有如期運行。

我打開火狐  360瀏覽器, 還是等兩個賬號同時登錄。

無奈之下把源碼下下載剖析(常乾的事兒, 喜歡搗騰這些東西)

 

判斷重複的類是ConcurrentSessionControlStrategy.java下的

checkAuthenticationAllowed這個函數的

最重要的一句話是:

sessionInformationList.get(j).expireNow();
這句強制T出了用戶, (設置爲過期)

如果想徹底刪除, 加上

sessionRegistry.removeSessionInformation(sessionInformationList.get(j).getSessionId());

即可,

這樣使用getAllPrincipals  則獲取不到被T出的用戶了,  其實原理不是直接刪除User對象, 只結束了它的sessionId,

因爲這個User可能不止對應着1個sessionId

 

 

我發現, 無論我怎麼配置,  sessionCount老是煩人的 0。    即使我手動配置了ConcurrentSessionControlStrategy這個bean也沒用(默認會自己調的)

 

無奈中想自己寫一個自定義的計數器控制, 但細想它這東西不至於這個小問題都出這麼大的漏洞吧?

 

現在的問題是:

如何讓 int sessionCount = sessions.size();  這句在第二個賬號登陸的時候不爲0。

 

於是我進入了sessionRegistry.getAllSessions(authentication.getPrincipal(), false);  這個函數。

 

也就是SessionRegistryImpl.java

 

    public List<SessionInformation> getAllSessions(Object principal, boolean includeExpiredSessions) {
        final Set<String> sessionsUsedByPrincipal = principals.get(principal);

 

這個函數是通過在一個HashMap裏拿到key value的。

 

而principals的聲明這樣寫。

 

private final Map<Object,Set<String>> principals = Collections.synchronizedMap(new HashMap<Object,Set<String>>());

 

 

現在的問題變爲了:

如何讓兩個principal  ,  也就是User, 也就是

public UserDetails loadUserByUsername(String username)

 

兩次登陸的時候返回的是同一個對象。

 

那麼如何做到兩次在不同瀏覽器登陸的時候返回的是同一個User?

 

答案是java的基礎, equal   hashcode方法重寫。

 

在User對象裏添加以下方法:

 

 

 涉及這方面的基礎請參考   http://blog.csdn.net/willielee/archive/2010/08/11/5804463.aspx

 

我就不浪費CSDN的硬盤空間了, 不過還是得貼出最後一句話:

HashMap的key判斷key是否相等也是從hashcode和equals是否相等判斷

 

 從上面可以看出, 我們之前登陸的用戶是存在    Map<Object,Set<String>> principals  的。

這個存儲結構是,  一個User  對應多個Set集合的sessionId。

所以要判斷用戶是否已存在登陸的了, 當然要重寫這2個方法。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章