Shiro - 限制并发人数登录与剔除

原文地址:https://www.cnblogs.com/leechenxiang/p/6171151.html


 
 
  1. import org.apache.shiro.cache.Cache;
  2. import org.apache.shiro.cache.CacheManager;
  3. import org.apache.shiro.session.Session;
  4. import org.apache.shiro.session.mgt.DefaultSessionKey;
  5. import org.apache.shiro.session.mgt.SessionManager;
  6. import org.apache.shiro.subject.Subject;
  7. import org.apache.shiro.web.filter.AccessControlFilter;
  8. import org.apache.shiro.web.util.WebUtils;
  9. import com.agood.pojo.ActiveUser;
  10. import javax.servlet.ServletRequest;
  11. import javax.servlet.ServletResponse;
  12. import javax.servlet.http.HttpServletRequest;
  13. import javax.servlet.http.HttpServletResponse;
  14. import java.io.Serializable;
  15. import java.util.Deque;
  16. import java.util.LinkedList;
  17. /**
  18. *
  19. * @Title: KickoutSessionControlFilter.java
  20. * @Package com.agood.bejavagod.controller.filter
  21. * @Description: 同一用户后登陆踢出前面的用户
  22. * Copyright: Copyright (c) 2016
  23. * Company:Nathan.Lee.Salvatore
  24. *
  25. * @author leechenxiang
  26. * @date 2016年12月12日 下午7:25:40
  27. * @version V1.0
  28. */
  29. public class KickoutSessionControlFilter extends AccessControlFilter {
  30. private String kickoutUrl; //踢出后到的地址
  31. private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户
  32. private int maxSession = 1; //同一个帐号最大会话数 默认1
  33. private SessionManager sessionManager;
  34. private Cache<String, Deque<Serializable>> cache;
  35. public void setKickoutUrl(String kickoutUrl) {
  36. this.kickoutUrl = kickoutUrl;
  37. }
  38. public void setKickoutAfter(boolean kickoutAfter) {
  39. this.kickoutAfter = kickoutAfter;
  40. }
  41. public void setMaxSession(int maxSession) {
  42. this.maxSession = maxSession;
  43. }
  44. public void setSessionManager(SessionManager sessionManager) {
  45. this.sessionManager = sessionManager;
  46. }
  47. public void setCacheManager(CacheManager cacheManager) {
  48. this.cache = cacheManager.getCache( "shiro-kickout-session");
  49. }
  50. @Override
  51. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
  52. return false;
  53. }
  54. @Override
  55. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
  56. Subject subject = getSubject(request, response);
  57. if(!subject.isAuthenticated() && !subject.isRemembered()) {
  58. //如果没有登录,直接进行之后的流程
  59. return true;
  60. }
  61. Session session = subject.getSession();
  62. ActiveUser user = (ActiveUser)subject.getPrincipal();
  63. String username = user.getUserName();
  64. Serializable sessionId = session.getId();
  65. // 同步控制
  66. Deque<Serializable> deque = cache.get(username);
  67. if(deque == null) {
  68. deque = new LinkedList<Serializable>();
  69. cache.put(username, deque);
  70. }
  71. //如果队列里没有此sessionId,且用户没有被踢出;放入队列
  72. if(!deque.contains(sessionId) && session.getAttribute( "kickout") == null) {
  73. deque.push(sessionId);
  74. }
  75. //如果队列里的sessionId数超出最大会话数,开始踢人
  76. while(deque.size() > maxSession) {
  77. Serializable kickoutSessionId = null;
  78. if(kickoutAfter) { //如果踢出后者
  79. kickoutSessionId = deque.removeFirst();
  80. } else { //否则踢出前者
  81. kickoutSessionId = deque.removeLast();
  82. }
  83. try {
  84. Session kickoutSession = sessionManager.getSession( new DefaultSessionKey(kickoutSessionId));
  85. if(kickoutSession != null) {
  86. //设置会话的kickout属性表示踢出了
  87. kickoutSession.setAttribute( "kickout", true);
  88. }
  89. } catch (Exception e) { //ignore exception
  90. }
  91. }
  92. //如果被踢出了,直接退出,重定向到踢出后的地址
  93. if (session.getAttribute( "kickout") != null) {
  94. //会话被踢出了
  95. try {
  96. subject.logout();
  97. } catch (Exception e) { //ignore
  98. }
  99. saveRequest(request);
  100. HttpServletRequest httpRequest = WebUtils.toHttp(request);
  101. if (ShiroFilterUtils.isAjax(httpRequest)) {
  102. HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
  103. httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_SESSION_EXPIRE);
  104. return false;
  105. } else {
  106. WebUtils.issueRedirect(request, response, kickoutUrl);
  107. return false;
  108. }
  109. }
  110. return true;
  111. }
  112. }

首先得要有个过滤器命名为:KickoutSessionControlFilter

然后在shiro.xml中需要这么定义:



 
 
  1. <property name="filters">
  2. <map>
  3. <entry key="kickout" value-ref="kickoutSessionControlFilter"/>
  4. </map>
  5. </property>


 
 
  1. <bean id="kickoutSessionControlFilter" class="com.agood.bejavagod.controller.filter.KickoutSessionControlFilter">
  2. <property name="cacheManager" ref="shiroEhcacheManager"/>
  3. <property name="sessionManager" ref="sessionManager"/>
  4. <!-- 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户 -->
  5. <property name="kickoutAfter" value="false"/>
  6. <!-- 同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录 -->
  7. <property name="maxSession" value="1"/>
  8. <property name="kickoutUrl" value="/login.action"/>
  9. </bean>
最后修改过滤器配置,拦截所有请求

/** = kickout,authc



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值