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 ...
随机推荐
- PostMan Request Export
- docker 部署jar包
docker volume create j1ls /var/lib/docker/volumes/j1/_data 上传jardocker run -it -d --name j1 -v j1:/h ...
- ffmpeg接收udp输入的h264文件流,推流到rtmp服务器
ffmpeg -re -f h264 -i udp://192.168.5.49:10002 -vcodec libx264 -f flv rtmp://192.168.5.155/live/1
- docker卷挂载与容器内外互相拷贝数据
一.宿主机与容器的挂载 docker可以支持把一个宿主机上的目录挂载到镜像里.命令如下: docker run -it -v /mydownload:/download nginx:v1 /bin/b ...
- z-score,beta,SE换算
换算公式:z-score=beta/SE 如果是从GWAS summary数据换算的话就是:z-score=Effect/StdErr 来源:https://www.biostars.org/p/14 ...
- ubuntu下MySQL忘记密码重置方法
方法一: 1):编辑mysqld.cnf文件 sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf 2):在文件中的skip-external-locking一行的下面 ...
- 淡sqlserver对like '%关键词%' 处理时的索引利用问题
说法一:百分号%通配符前置会让SQL查询不走索引,改走全表扫描.这种说法很流行 结论是错误的 事实上这种说法不太准确 通配符%前置会让SQL查找索引时效率极速下降,但在大多数情况下还是会走索引(不需要 ...
- C#基于RabbitMQ实现客户端之间消息通讯实战演练
一.背景介绍和描述 MQ消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.何时需要消息队列?当你需要使用 ...
- AppCrawler运用总结
一.环境 1.环境准备:安装安卓SDK + 真机 + appcrawler-2.1.3.jar 在放 appcrawler-2.1.0.jar 的文件夹下执行以下命令: 1.生成yml的demo:ja ...
- AppCrawler安装使用
百度网盘: https://pan.baidu.com/s/1bpmR3eJ mac下安装appium 真机或者模拟器均可. 确保adb devices可以看到就行 启动appium 启动appium ...