在某些項目中可能會遇到如每個賬戶同時只能有一個人登錄或幾個人同時登錄,如果同時有多人登錄:要么不讓后者登錄;要么踢出前者登錄(強制退出)。比如spring security就直接提供了相應的功能;Shiro的話沒有提供默認實現,不過可以很容易的在Shiro中加入這個功能。
公司主營業務:成都網站設計、成都網站制作、移動網站開發等業務。幫助企業客戶真正實現互聯網宣傳,提高企業的競爭能力。創新互聯公司是一支青春激揚、勤奮敬業、活力青春激揚、勤奮敬業、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰,讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創新互聯公司推出鄂城免費做網站回饋大家。
通過Shiro Filter機制擴展KickoutSessionControlFilter完成。
首先來看看如何配置使用(spring-config-shiro.xml)
kickoutSessionControlFilter用于控制并發登錄人數的
Java代碼
<bean id="kickoutSessionControlFilter" class="com.github.zhangkaitao.shiro.chapter18.web.shiro.filter.KickoutSessionControlFilter"> <property name="cacheManager" ref="cacheManager"/> <property name="sessionManager" ref="sessionManager"/> <property name="kickoutAfter" value="false"/> <property name="maxSession" value="2"/> <property name="kickoutUrl" value="/login?kickout=1"/> </bean>
cacheManager:使用cacheManager獲取相應的cache來緩存用戶登錄的會話;用于保存用戶—會話之間的關系的;
sessionManager:用于根據會話ID,獲取會話進行踢出操作的;
kickoutAfter:是否踢出后來登錄的,默認是false;即后者登錄的用戶踢出前者登錄的用戶;
maxSession:同一個用戶最大的會話數,默認1;比如2的意思是同一個用戶允許最多同時兩個人登錄;
kickoutUrl:被踢出后重定向到的地址;
shiroFilter配置
Java代碼
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login"/> <property name="filters"> <util:map> <entry key="authc" value-ref="formAuthenticationFilter"/> <entry key="sysUser" value-ref="sysUserFilter"/> <entry key="kickout" value-ref="kickoutSessionControlFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /login = authc /logout = logout /authenticated = authc /** = kickout,user,sysUser </value> </property> </bean>
此處配置除了登錄等之外的地址都走kickout攔截器進行并發登錄控制。
測試
此處因為maxSession=2,所以需要打開3個瀏覽器(需要不同的瀏覽器,如IE、Chrome、Firefox),分別訪問http://localhost:8080/chapter18/進行登錄;然后刷新第一次打開的瀏覽器,將會被強制退出,如顯示下圖:

KickoutSessionControlFilter核心代碼:
Java代碼
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = getSubject(request, response);
if(!subject.isAuthenticated() && !subject.isRemembered()) {
//如果沒有登錄,直接進行之后的流程
return true;
}
Session session = subject.getSession();
String username = (String) subject.getPrincipal();
Serializable sessionId = session.getId();
//TODO 同步控制
Deque<Serializable> deque = cache.get(username);
if(deque == null) {
deque = new LinkedList<Serializable>();
cache.put(username, deque);
}
//如果隊列里沒有此sessionId,且用戶沒有被踢出;放入隊列
if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
deque.push(sessionId);
}
//如果隊列里的sessionId數超出最大會話數,開始踢人
while(deque.size() > maxSession) {
Serializable kickoutSessionId = null;
if(kickoutAfter) { //如果踢出后者
kickoutSessionId = deque.removeFirst();
} else { //否則踢出前者
kickoutSessionId = deque.removeLast();
}
try {
Session kickoutSession =
sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
if(kickoutSession != null) {
//設置會話的kickout屬性表示踢出了
kickoutSession.setAttribute("kickout", true);
}
} catch (Exception e) {//ignore exception
}
}
//如果被踢出了,直接退出,重定向到踢出后的地址
if (session.getAttribute("kickout") != null) {
//會話被踢出了
try {
subject.logout();
} catch (Exception e) { //ignore
}
saveRequest(request);
WebUtils.issueRedirect(request, response, kickoutUrl);
return false;
}
return true;
} 此處使用了Cache緩存用戶名—會話id之間的關系;如果量比較大可以考慮如持久化到數據庫/其他帶持久化的Cache中;另外此處沒有并發控制的同步實現,可以考慮根據用戶名獲取鎖來控制,減少鎖的粒度。
總結
以上所述是小編給大家介紹的shiro并發人數登錄控制的實現代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對創新互聯網站的支持!
新聞名稱:shiro并發人數登錄控制的實現代碼
標題URL:http://www.yijiale78.com/article20/gsogco.html
成都網站建設公司_創新互聯,為您提供動態網站、網站維護、軟件開發、靜態網站、品牌網站制作、網站設計公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯