org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案
org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案
背景描述
SpringBoot项目,使用Shiro进行权限管理。测试过程中发现执行文件导入时最开始一切正常,但是导入几次之后再次执行导入就会报错,此时执行其他功能一切正常

排查过程
- [x] 1. 网上搜索,大部分都是说法如下:
Shiro的Cookie名称默认是JSESSIONID,与servlet容器冲突。修改Shiro的SessionID即可
- [x] 2. 假如是上述原因,应该从登录开始就出问题,而不应该是极个别操作出现问题。而我这里只有多次导入之后出问题,并且此时其他功能还是正常的。因此排除这个原因,自己进行排查。
- [x] 3. 因为只有导入出现这个问题,其他功能都一切正常;因此怀疑是导入的代码存在问题。
- [x] 4. 排查导入代码发现,只有在执行保存语句的时候获取当前用户使用了Shiro相关代码,因此怀疑此处出现问题。
this.operator = (String) SecurityUtils.getSubject().getPrincipal();
- [x] 5. 在此处断点发现,手动新增数据和批量导入数据都执行该语句,但两次获取的Subject不一致。因此阅读源码进行排查。
// 从SecurityUtils中获取Subject源码如下
// package: org.apache.shiro.SecurityUtils
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject(); // ①
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
// 继续跟进上面①中的方法
// package: org.apache.shiro.util.ThreadContext
public static Subject getSubject() {
return (Subject) get(SUBJECT_KEY); // ②
}
// 继续跟进上面②中的方法
// package: org.apache.shiro.util.ThreadContext
public static Object get(Object key) {
if (log.isTraceEnabled()) {
String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
log.trace(msg);
}
Object value = getValue(key); // ③
if ((value != null) && log.isTraceEnabled()) {
String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" +
key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]";
log.trace(msg);
}
return value;
}
// 继续跟进上面③中的方法
// package: org.apache.shiro.util.ThreadContext
private static Object getValue(Object key) {
Map<Object, Object> perThreadResources = resources.get(); // ④
return perThreadResources != null ? perThreadResources.get(key) : null;
}
// 上面④中的resources在ThreadContext中定义如下
// package: org.apache.shiro.util.ThreadContext
private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();
- [x] 6. 根据上面对源码的跟踪,发现Subject是与ThreadLocal也就是线程绑定的。获取Subject时先获取当前线程绑定的Subject,若没有则重新创建并绑定到当前线程。而我导入的时候为了提高导入效率,使用了多线程。到此就发现问题的原因了
问题原因
- 假设项目中线程池设置核心线程数量为10,而核心线程默认是不会被超时回收的
ps: 可通过threadPoolExecutor.allowCoreThreadTimeOut(true);设置核心线程超时回收
- 当用户A登录后,执行导入操作,从线程池中拿出5个线程,此时这5个线程将绑定用户A的Subject
- 当用户A多次执行导入操作后,线程池全部核心线程与用户A的Subject绑定。用户A退出登录后,线程池并不会将核心线程进行销毁。
- 后续用户B登录,再次执行导入操作,此时线程池分配线程进行操作,但此时所有的线程都已与用户A绑定,因此获取到的Subject都是用户A的Subject,从Subject中获取session时此session已被销毁,因此报错
// 根据sessionId获取session,获取为空则报错
// package: org.apache.shiro.session.mgt.eis.AbstractSessionDAO
public Session readSession(Serializable sessionId) throws UnknownSessionException {
Session s = doReadSession(sessionId);
if (s == null) {
throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
}
return s;
}
解决方案
多线程时不要使用Shiro相关代码。将用户名作为参数传入,不再单独获取。
PS: 该解决方案不适用于所有情况,请根据实际情况按照上述排查步骤进行排查。
org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案的更多相关文章
- 解决org.apache.shiro.session.UnknownSessionException: There is no session with id的问题
一.背景 最近在整合了Spring+Shiro+Redis实现tomcat集群session共享的问题之后,发布以后运行以后发现老是会出现:org.apache.shiro.session.Unkno ...
- Apache Shiro 1.3.2入门
简介 Apache Shiro是一个功能强大且灵活的开放源代码安全框架,可以清楚地处理认证,授权,企业会话管理和加密.Apache Shiro的首要目标是易于使用和理解.有时候安全性可能非常复杂和痛苦 ...
- [转]在 Web 项目中应用 Apache Shiro
目录[-] 用户权限模型 图 1. 用户权限模型 认证与授权 Shiro 认证与授权处理过程 Shiro Realm 清单 1. 实现自己的 JDBC Realm 为何对 Shiro 情有独钟 与 S ...
- 在 Web 项目中应用 Apache Shiro
Apache Shiro 是功能强大并且容易集成的开源权限框架,它能够完成认证.授权.加密.会话管理等功能.认证和授权为权限控制的核心,简单来说,"认证"就是证明你是谁? Web ...
- Apache Shiro 开源权限框架
在 Web 项目中应用 Apache Shiro 开源权限框架 Apache Shiro 是功能强大并且容易集成的开源权限框架,它能够完成认证.授权.加密.会话管理等功能.认证和授权为权限控制的核心, ...
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (八) web集群时session同步的3种方法
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- org.apache.shiro.session.InvalidSessionException: java.lang.IllegalStateException: getAttribute: Session already invalidated] with root cause
1.遇到以下异常,找了好长时间,终于解决,报的异常如下: 七月 07, 2017 3:02:16 下午 org.apache.catalina.core.StandardWrapperValve in ...
随机推荐
- EMQ 与 mqtt 与 IOT设备
1.IOT设备的特性 IOT(物联网things of internet)设备和传统的智能设备有什么区别,笔者总结下的IOT设备有如下特点: 硬件能力差(存储能力基本只有几MB,CPU频率低连使用HT ...
- mysql索引原理及优化(二)
索引原理分析:数据结构 索引是最常见的慢查询优化方式其是一种优化查询的数据结构,MySql中的索引是用B+树实现,而B+树就是一种数据结构,可以优化查询速度,可以利用索引快速查找数据,优化查询. 可以 ...
- 微信小程序实例:分享给一个人还是分享到群的判断代码
微信小程序的分享功能,在最新版库的ide上已经不能拿到分享回调了,官方api也删除了对应的回调函数,看样子是砍掉了,不过真机测试还是可以的,话不多说,上代码: /* // 分享功能回调 onLoad: ...
- WAL streaming (max_wal_senders > 0) requires wal_level "replica" or "logical"
初次使用pg的11版本,执行以下操作修改归wal_level设置: alter system set set wal_level='minimal'; 尝试重启pg,发现重启失败,并报错: waiti ...
- Android - Button(按钮)的响应点击事件的4种写法
Button控件setOnclickListener(View.OnClickListener listener)来接收一个点击事件的监听器 自定义一个点击事件监听器类让其实现View.OnClick ...
- centos6.10中部署percona-mysql双实例的方法
centos6.10中部署percona-mysql双实例的方法 数据库的同步关系:192.168.11.53(master) --> slave(192.168.10.189) --> ...
- Laya微信小游戏的动态资源
版本2.1.1. 由于有4m包限制,所以一般小游戏项目分成主包+远程资源. 现在我新建一个remote目录,该目录下资源不发布到微信小游戏目录下,而是服务器远程加载. 发布时,勾线是否提取本地包 远程 ...
- PHP 基于 Jenkins ansible 动态选择版本进行自动化部署与回滚(第二版)
PHP 基于 Jenkins ansible 动态选择版本进行自动化部署与回滚(第二版) 先看流程图: 大概介绍一下: 版本选择使用jenkins 中的 git parameter 插件实现 回滚方式 ...
- cmd 连接oracle
第一步: sqlplus/nolog 第二步: conn 数据库名/密码@ip:端口/database: conn bill:/orcl 如果是连接不上. 报错信息为 Oracle ORA-0103 ...
- [LeetCode] 96. Unique Binary Search Trees 唯一二叉搜索树
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...