package com.ots.framework.shiro.web.filter.kickout; import com.fasterxml.jackson.databind.ObjectMapper; import com.ots.common.constant.ShiroConstants; import com.ots.common.utils.ServletUtils; import com.ots.common.utils.security.ShiroUtils; import com.ots.framework.web.domain.AjaxResult; import com.ots.project.system.user.domain.User; 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 javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Serializable; import java.util.ArrayDeque; import java.util.Deque; public class KickoutSessionFilter extends AccessControlFilter { private final static ObjectMapper objectMapper = new ObjectMapper(); private int maxSession = -1; private Boolean kickoutAfter = false; private String kickoutUrl; private SessionManager sessionManager; private Cache> cache; @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { return false; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { Subject subject = getSubject(request, response); if (!subject.isAuthenticated() && !subject.isRemembered() || maxSession == -1) { return true; } try { Session session = subject.getSession(); User user = ShiroUtils.getSysUser(); String loginName = user.getLoginName(); Serializable sessionId = session.getId(); Deque deque = cache.get(loginName); if (deque == null) { deque = new ArrayDeque(); } if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) { deque.push(sessionId); cache.put(loginName, deque); } while (deque.size() > maxSession) { Serializable kickoutSessionId = null; if (kickoutAfter) { kickoutSessionId = deque.removeFirst(); } else { kickoutSessionId = deque.removeLast(); } cache.put(loginName, deque); try { Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); if (null != kickoutSession) { kickoutSession.setAttribute("kickout", true); } } catch (Exception e) { } } if ((Boolean) session.getAttribute("kickout") != null && (Boolean) session.getAttribute("kickout") == true) { subject.logout(); saveRequest(request); return isAjaxResponse(request, response); } return true; } catch (Exception e) { return isAjaxResponse(request, response); } } private boolean isAjaxResponse(ServletRequest request, ServletResponse response) throws IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; if (ServletUtils.isAjaxRequest(req)) { AjaxResult ajaxResult = AjaxResult.error("您已在别处登录,请您修改密码或重新登录"); ServletUtils.renderString(res, objectMapper.writeValueAsString(ajaxResult)); } else { WebUtils.issueRedirect(request, response, kickoutUrl); } return false; } public void setMaxSession(int maxSession) { this.maxSession = maxSession; } public void setKickoutAfter(boolean kickoutAfter) { this.kickoutAfter = kickoutAfter; } public void setKickoutUrl(String kickoutUrl) { this.kickoutUrl = kickoutUrl; } public void setSessionManager(SessionManager sessionManager) { this.sessionManager = sessionManager; } public void setCacheManager(CacheManager cacheManager) { this.cache = cacheManager.getCache(ShiroConstants.SYS_USERCACHE); } }