Shiro并发登录人数控制遇到的问题和解决
shiro并发登录人数控制遇到的问题和解决
- 问题1:KickoutSessionControlFilter不起作用
- 问题2:KickoutSessionControlFilter中cache为null空指针异常
- 问题3:服务器重启后首页访问:subject.getPrincipal()报ClassCastException异常
- 系统环境
- 参考资料
问题1:KickoutSessionControlFilter不起作用
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {}中设置:
{
…
filters.put(“kickout”, new KickoutSessionControlFilter());
…
filterMap.put("/**", “kickout”);
}
结果:KickoutSessionControlFilter不起作用。
进一步查看代码:
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {ShiroPermsFilterFactoryBean shiroFilter = new ShiroPermsFilterFactoryBean();...Map<String, Filter> filters = new HashMap<>(3);filters.put("kickout", new KickoutSessionControlFilter());shiroFilter.setFilters(filters);Map<String, String> filterMap = new LinkedHashMap<>(16);...filterMap.put("/**", "kickout");shiroFilter.setFilterChainDefinitionMap(filterMap);return shiroFilter;}
查看代码行:shiroFilter.setFilterChainDefinitionMap(filterMap);
setFilterChainDefinitionMap点进去:
public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {...filterChainDefinitionMap.put("/**", "user");super.setFilterChainDefinitionMap(filterChainDefinitionMap);...
}
分析:
filterMap.put("/**", "kickout");
和
filterChainDefinitionMap.put("/**", "user");
操作的是同一个对象,
filterChainDefinitionMap是一个Map,
key一样,put会覆盖掉前面的值。
解决:
改
filterChainDefinitionMap.put("/**", "kickout,user");
问题2:KickoutSessionControlFilter中cache为null空指针异常
public class KickoutSessionControlFilter extends AccessControlFilter {private Cache<String, Deque<Serializable>> cache;...@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {...Deque<Serializable> deque = cache.get(username);...deque = new LinkedList<Serializable>();cache.put(username, deque);...}
}
查看:ShiroConfig.java中session管理器SessionManager
@Beanpublic SessionManager sessionManager(GlobalProperties globalProperties){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(true);sessionManager.setSessionIdUrlRewritingEnabled(false);sessionManager.setDeleteInvalidSessions(true);if (globalProperties.isRedisSessionDao()) {// 开启redis会话管理器sessionManager.setSessionFactory(new UserSessionFactory());sessionManager.setSessionDAO(new UserSessionDAO());List<SessionListener> sessionListeners = new ArrayList<>();sessionListeners.add(new UserSessionListener());sessionManager.setSessionListeners(sessionListeners);}return sessionManager;}
发现:框架没有配置CacheManager,有配置redis会话管理,改用RedisCacheManager。
解决:
public class KickoutSessionControlFilter extends AccessControlFilter {private Cache<String, Deque<Serializable>> cache;...@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {...RedisCacheManager redisCacheManager = (RedisCacheManager) SpringContextUtils.getBean("redisCacheManager");...LinkedList<Serializable> linkedList = new LinkedList<Serializable>();...linkedList = (LinkedList<Serializable>) redisCacheManager.get(username);...redisCacheManager.set(username,linkedList);...}
}
问题3:服务器重启后首页访问:subject.getPrincipal()报ClassCastException异常
@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {Subject subject = getSubject(request, response);if(!subject.isAuthenticated() && !subject.isRemembered()) {//如果没有登录,直接进行之后的流程return true;}Session session = subject.getSession();SysUserEntity user = (SysUserEntity) subject.getPrincipal();username= user.getUsername();...
}
一番打端点分析:
用户登陆状态下,服务器重启后:
subject.isAuthenticated()仍然为true。“//如果没有登录,直接进行之后的流程”该步骤不能进入,未return true,继续后续执行。
且session仍然在,未失效。
(SysUserEntity) subject.getPrincipal();
强转报异常,原因不明。
暂时解决方法:try捕获ClassCastException时调用subject.logout();登出。定向到首页。
try {SysUserEntity user = (SysUserEntity) subject.getPrincipal();username= user.getUsername();} catch (ClassCastException cce) {//服务器重启后,session仍然在,但subject.getPrincipal会有强转异常try {subject.logout();} catch (Exception e) { //ignore}saveRequest(request);httpServletRequest.setAttribute("errorMsg", "登录超时,请重新登录");httpServletRequest.getRequestDispatcher("/login").forward(request, response);return false;}
系统环境
springboot
参考资料
https://blog.csdn.net/qq_33556185/article/details/51744004
https://www.w3cschool.cn/shiro/epht1ifg.html
Shiro并发登录人数控制遇到的问题和解决相关推荐
- shiro并发登录人数控制
在某些项目中可能会遇到如每个账户同时只能有一个人登录或几个人同时登录,如果同时有多人登录:要么不让后者登录:要么踢出前者登录(强制退出).比如spring security就直接提供了相应的功能:Sh ...
- springboot + shiro 尝试登录次数限制与并发登录人数控制
源码项目地址 尝试登录次数控制实现 实现原理 Realm在验证用户身份的时候,要进行密码匹配.最简单的情况就是明文直接匹配,然后就是加密匹配,这里的匹配工作则就是交给CredentialsMatche ...
- SpringBoot 实现并发登录人数控制
作者丨殷天文 www.jianshu.com/p/b6f5ec98d790 今天跟大家分享SpringBoot 实现并发登录人数控制的知识. 1 SpringBoot 实现并发登录人数控制 通常系统都 ...
- 模仿爱奇艺账号登录限制人数,SpringBoot 并发登录人数控制,踢人功能
通常系统都会限制同一个账号的登录人数,多人登录要么限制后者登录,要么踢出前者,Spring Security 提供了这样的功能,本文讲解一下在没有使用Security的时候如何手动实现这个功能 技术选 ...
- SpringBoot 并发登录人数控制
点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 作者:殷天文 www.jianshu.com/p/b6f5ec98d790 技术经验交流:点击入 ...
- 如何用 SpringBoot 实现并发登录人数控制(附代码)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 作者 ...
- springboot + shiro之登录人数限制、登录判断重定向、session时间设置
springboot + shiro之登录人数控制 项目 前篇:spring boot + mybatis + layui + shiro后台权限管理系统:https://blog.51cto.com ...
- 厉害了,教你用 Spring Boot 控制并发登录人数
作者:殷天文 www.jianshu.com/p/b6f5ec98d790 通常系统都会限制同一个账号的登录人数,多人登录要么限制后者登录,要么踢出前者,Spring Security 提供了这样的功 ...
- 【Shiro】7、Shiro实现控制用户并发登录并踢人下线
在传统的项目中,同一账户是允许多人同时登录在线的,有的使用场景恰恰是不允许多人同时在线的,那么我们可以通过 Shiro 来控制并发登录,并实现后登录的用户,挤掉前面登录的用户 1.并发登录过滤器 pa ...
最新文章
- 揭露Windows中各种不老实的服务
- 2.2.6 学习率衰减
- 清除掉AD的相关属性!
- 产品经理必懂技术术语(前端类)
- 从 CVE-2020-1048 到 CVE-2020-17001:Windows打印机模块中多个提权漏洞分析
- php条件语句中大括号必须,PHP条件,括号需要?
- 思科又发紧急安全通告 IOS集群管理协议漏洞和Struts2漏洞 有影响产品列表及应对措施了...
- 东北大学金工实习理论考试重点
- NoSQL数据库应用
- Firebug工具离线安装
- 高低压恒流斩波步进电机驱动器设计
- 只有PHP大牛才能读懂的内涵图
- 学驾照,科目一计分题
- 【Altium designer】常用的线宽和过孔尺寸
- Java打印101-150之间所有的质数
- 重磅!L4级自动驾驶硬件方案来啦!
- 安全合规/GDPR--24--研究:GDPR合规体系设立与执行
- 蓝牙-HFP概览-转
- 华为笔试题 linux c,华为C/C++笔试题 2
- [源码和文档分享]JAVA实现基于k-means聚类算法实现微博舆情热点分析系统