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,若没有则重新创建并绑定到当前线程。而我导入的时候为了提高导入效率,使用了多线程。到此就发现问题的原因了

问题原因

  1. 假设项目中线程池设置核心线程数量为10,而核心线程默认是不会被超时回收的

ps: 可通过threadPoolExecutor.allowCoreThreadTimeOut(true);设置核心线程超时回收

  1. 当用户A登录后,执行导入操作,从线程池中拿出5个线程,此时这5个线程将绑定用户A的Subject
  2. 当用户A多次执行导入操作后,线程池全部核心线程与用户A的Subject绑定。用户A退出登录后,线程池并不会将核心线程进行销毁。
  3. 后续用户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]的解决方案的更多相关文章

  1. 解决org.apache.shiro.session.UnknownSessionException: There is no session with id的问题

    一.背景 最近在整合了Spring+Shiro+Redis实现tomcat集群session共享的问题之后,发布以后运行以后发现老是会出现:org.apache.shiro.session.Unkno ...

  2. Apache Shiro 1.3.2入门

    简介 Apache Shiro是一个功能强大且灵活的开放源代码安全框架,可以清楚地处理认证,授权,企业会话管理和加密.Apache Shiro的首要目标是易于使用和理解.有时候安全性可能非常复杂和痛苦 ...

  3. [转]在 Web 项目中应用 Apache Shiro

    目录[-] 用户权限模型 图 1. 用户权限模型 认证与授权 Shiro 认证与授权处理过程 Shiro Realm 清单 1. 实现自己的 JDBC Realm 为何对 Shiro 情有独钟 与 S ...

  4. 在 Web 项目中应用 Apache Shiro

    Apache Shiro 是功能强大并且容易集成的开源权限框架,它能够完成认证.授权.加密.会话管理等功能.认证和授权为权限控制的核心,简单来说,"认证"就是证明你是谁? Web ...

  5. Apache Shiro 开源权限框架

    在 Web 项目中应用 Apache Shiro 开源权限框架 Apache Shiro 是功能强大并且容易集成的开源权限框架,它能够完成认证.授权.加密.会话管理等功能.认证和授权为权限控制的核心, ...

  6. Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  7. Apache shiro集群实现 (八) web集群时session同步的3种方法

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  8. Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  9. 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 ...

随机推荐

  1. PostMan Request Export

  2. docker 部署jar包

    docker volume create j1ls /var/lib/docker/volumes/j1/_data 上传jardocker run -it -d --name j1 -v j1:/h ...

  3. 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

  4. docker卷挂载与容器内外互相拷贝数据

    一.宿主机与容器的挂载 docker可以支持把一个宿主机上的目录挂载到镜像里.命令如下: docker run -it -v /mydownload:/download nginx:v1 /bin/b ...

  5. z-score,beta,SE换算

    换算公式:z-score=beta/SE 如果是从GWAS summary数据换算的话就是:z-score=Effect/StdErr 来源:https://www.biostars.org/p/14 ...

  6. ubuntu下MySQL忘记密码重置方法

    方法一: 1):编辑mysqld.cnf文件 sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf 2):在文件中的skip-external-locking一行的下面 ...

  7. 淡sqlserver对like '%关键词%' 处理时的索引利用问题

    说法一:百分号%通配符前置会让SQL查询不走索引,改走全表扫描.这种说法很流行 结论是错误的 事实上这种说法不太准确 通配符%前置会让SQL查找索引时效率极速下降,但在大多数情况下还是会走索引(不需要 ...

  8. C#基于RabbitMQ实现客户端之间消息通讯实战演练

    一.背景介绍和描述 MQ消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.何时需要消息队列?当你需要使用 ...

  9. AppCrawler运用总结

    一.环境 1.环境准备:安装安卓SDK + 真机 + appcrawler-2.1.3.jar 在放 appcrawler-2.1.0.jar 的文件夹下执行以下命令: 1.生成yml的demo:ja ...

  10. AppCrawler安装使用

    百度网盘: https://pan.baidu.com/s/1bpmR3eJ mac下安装appium 真机或者模拟器均可. 确保adb devices可以看到就行 启动appium 启动appium ...