本文主要是介绍Shiro - 限制并发人数登录与剔除,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原文地址:https://www.cnblogs.com/leechenxiang/p/6171151.html
- 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.agood.pojo.ActiveUser;
-
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import java.io.Serializable;
- import java.util.Deque;
- import java.util.LinkedList;
-
- /**
- *
- * @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;
- 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;
- }
- }
首先得要有个过滤器命名为:KickoutSessionControlFilter
然后在shiro.xml中需要这么定义:
- <property name="filters">
- <map>
- <entry key="kickout" value-ref="kickoutSessionControlFilter"/>
- </map>
- </property>
- <bean id="kickoutSessionControlFilter" class="com.agood.bejavagod.controller.filter.KickoutSessionControlFilter">
- <property name="cacheManager" ref="shiroEhcacheManager"/>
- <property name="sessionManager" ref="sessionManager"/>
- <!-- 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户 -->
- <property name="kickoutAfter" value="false"/>
- <!-- 同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录 -->
- <property name="maxSession" value="1"/>
- <property name="kickoutUrl" value="/login.action"/>
- </bean>
最后修改过滤器配置,拦截所有请求
/** = kickout,authc
这篇关于Shiro - 限制并发人数登录与剔除的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!