欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Shiro并发登录人数控制遇到的问题和解决

发布时间:2025/3/11 编程问答 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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并发登录人数控制遇到的问题和解决的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。