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

2024-04-17 06:38

本文主要是介绍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



这篇关于Shiro - 限制并发人数登录与剔除的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/911060

相关文章

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

高并发环境中保持幂等性

在高并发环境中保持幂等性是一项重要的挑战。幂等性指的是无论操作执行多少次,其效果都是相同的。确保操作的幂等性可以避免重复执行带来的副作用。以下是一些保持幂等性的常用方法: 唯一标识符: 请求唯一标识:在每次请求中引入唯一标识符(如 UUID 或者生成的唯一 ID),在处理请求时,系统可以检查这个标识符是否已经处理过,如果是,则忽略重复请求。幂等键(Idempotency Key):客户端在每次

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为