-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
149 additions
and
2 deletions.
There are no files selected for viewing
136 changes: 136 additions & 0 deletions
136
.../leecx-mng-web/src/main/java/com/itzixi/web/shiro/filter/KickoutSessionControlFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package com.itzixi.web.shiro.filter; | ||
|
||
import java.io.Serializable; | ||
import java.util.Deque; | ||
import java.util.LinkedList; | ||
|
||
import javax.servlet.ServletRequest; | ||
import javax.servlet.ServletResponse; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import org.apache.shiro.cache.Cache; | ||
import org.apache.shiro.cache.CacheManager; | ||
import org.apache.shiro.session.Session; | ||
import org.apache.shiro.session.mgt.DefaultSessionKey; | ||
import org.apache.shiro.session.mgt.SessionManager; | ||
import org.apache.shiro.subject.Subject; | ||
import org.apache.shiro.web.filter.AccessControlFilter; | ||
import org.apache.shiro.web.util.WebUtils; | ||
|
||
import com.itzixi.pojo.ActiveUser; | ||
|
||
/** | ||
* | ||
* @Title: KickoutSessionControlFilter.java | ||
* @Package com.agood.bejavagod.controller.filter | ||
* @Description: 同一用户后登陆踢出前面的用户 | ||
* Copyright: Copyright (c) 2016 | ||
* Company:Nathan.Lee.Salvatore | ||
* | ||
* @author leechenxiang | ||
* @date 2016年12月12日 下午7:25:40 | ||
* @version V1.0 | ||
*/ | ||
public class KickoutSessionControlFilter extends AccessControlFilter { | ||
|
||
private String kickoutUrl; //踢出后到的地址 | ||
private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户 | ||
private int maxSession = 1; //同一个帐号最大会话数 默认1 | ||
|
||
private SessionManager sessionManager; | ||
|
||
// TODO 分布式集群环境下,需要改为redis | ||
private Cache<String, Deque<Serializable>> cache; | ||
|
||
public void setKickoutUrl(String kickoutUrl) { | ||
this.kickoutUrl = kickoutUrl; | ||
} | ||
|
||
public void setKickoutAfter(boolean kickoutAfter) { | ||
this.kickoutAfter = kickoutAfter; | ||
} | ||
|
||
public void setMaxSession(int maxSession) { | ||
this.maxSession = maxSession; | ||
} | ||
|
||
public void setSessionManager(SessionManager sessionManager) { | ||
this.sessionManager = sessionManager; | ||
} | ||
|
||
public void setCacheManager(CacheManager cacheManager) { | ||
this.cache = cacheManager.getCache("shiro-kickout-session"); | ||
} | ||
|
||
@Override | ||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { | ||
return false; | ||
} | ||
|
||
@Override | ||
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(); | ||
ActiveUser user = (ActiveUser)subject.getPrincipal(); | ||
String username = user.getUsername(); | ||
Serializable sessionId = session.getId(); | ||
|
||
// 同步控制, 同步在本机的缓存中是有效的,但是一旦放入集群中,就会失效 | ||
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); | ||
|
||
HttpServletRequest httpRequest = WebUtils.toHttp(request); | ||
if (ShiroFilterUtils.isAjax(httpRequest)) { | ||
HttpServletResponse httpServletResponse = WebUtils.toHttp(response); | ||
httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_SESSION_EXPIRE); | ||
return false; | ||
} else { | ||
WebUtils.issueRedirect(request, response, kickoutUrl); | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters