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

相关文章

Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南

《SpringBoot基于JWT优化SpringSecurity无状态登录实战指南》本文介绍如何使用JWT优化SpringSecurity实现无状态登录,提高接口安全性,并通过实际操作步骤... 目录Spring Boot 实战:基于 JWT 优化 Spring Security 无状态登录一、先搞懂:为什

python协程实现高并发的技术详解

《python协程实现高并发的技术详解》协程是实现高并发的一种非常高效的方式,特别适合处理大量I/O操作的场景,本文我们将简单介绍python协程实现高并发的相关方法,需要的小伙伴可以了解下... 目录核心概念与简单示例高并发实践:网络请求协程如何实现高并发:核心技术协作式多任务与事件循环非阻塞I/O与连接

在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)

《在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)》DataGrip是JetBrains公司出品的一款现代化数据库管理工具,支持多种数据库系统,包括MySQL,:本文主要介绍在D... 目录前言一、登录 mysql 服务器1.1 打开 DataGrip 并添加数据源1.2 配置 MySQL

Springboot中JWT登录校验及其拦截器实现方法

《Springboot中JWT登录校验及其拦截器实现方法》:本文主要介绍Springboot中JWT登录校验及其拦截器实现方法的相关资料,包括引入Maven坐标、获取Token、JWT拦截器的实现... 目录前言一、JWT是什么?二、实现步骤1.引入Maven坐标2.获取Token3.JWT拦截器的实现4.

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java 结构化并发Structured Concurrency实践举例

《Java结构化并发StructuredConcurrency实践举例》Java21结构化并发通过作用域和任务句柄统一管理并发生命周期,解决线程泄漏与任务追踪问题,提升代码安全性和可观测性,其核心... 目录一、结构化并发的核心概念与设计目标二、结构化并发的核心组件(一)作用域(Scopes)(二)任务句柄

90%的人第一步就错了! 顺利登录wifi路由器后台的技巧

《90%的人第一步就错了!顺利登录wifi路由器后台的技巧》登录Wi-Fi路由器,其实就是进入它的后台管理页面,很多朋友不知道该怎么进入路由器后台设置,感兴趣的朋友可以花3分钟了解一下... 你是不是也遇到过这种情况:家里网速突然变慢、想改WiFi密码却不知道从哪进路由器、新装宽带后完全不知道怎么设置?别慌

k8s容器放开锁内存限制问题

《k8s容器放开锁内存限制问题》nccl-test容器运行mpirun时因NCCL_BUFFSIZE过大导致OOM,需通过修改docker服务配置文件,将LimitMEMLOCK设为infinity并... 目录问题问题确认放开容器max locked memory限制总结参考:https://Access

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2