rg.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]

1、背景

批量操作,用户A登录执行完批量操作,用户B登录在执行批量操作的时候报错

2、排查过程

 2.1 网上搜的大部分都是:Shiro的Cookie名称默认是JSESSIONID,与servlet容器冲突。修改Shiro的SessionID即可。但是如果是这个问题,用户B应该是无法登录的!所以还是shiro代码出的问题!

2.2 批量操作代码只有子线程中获取了当前登录人信息的代码与shiro有关,所以问题还是在这!

vo.setOperatorId(ShiroUtils.getUserId());
vo.setOperatorName(ShiroUtils.getUserEntity().getUsername());

进入getUserEntity()

public static SysUserEntity getUserEntity() {
		if (isLogin()) {
			return (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
		}
		return null;
	}

进入SecurityUtils.getSubject()

public static Subject getSubject() {
    Subject subject = ThreadContext.getSubject();
    if (subject == null) {
      subject = (new Builder()).buildSubject();
      ThreadContext.bind(subject);
    }

    return subject;
  }

进入ThreadContext.getSubject()

public static Subject getSubject() {
    return (Subject)get(SUBJECT_KEY);
  }


  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;
  }

进入getValue(key)

  private static Object getValue(Object key) {
    Map<Object, Object> perThreadResources = (Map)resources.get();
    return perThreadResources != null ? perThreadResources.get(key) : null;
  }

进入(Map)resources.get();

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

一路走来发现:Subject是与ThreadLocal也就是线程绑定的,这就是造成获取用户错误的原因。我们的线程在执行完毕的时候并没有清除ThreadLocal中的值,导致后面的任务重用现在的LocalMap。

3、解决方法:在线程池中使用Shiro的情况下,子线程无法获取上层线程的shiro相关变量,当前用户需要在外层设置进去,eg:将子线程中调用Shiro获取当前登录人信息的代码,提到上层线程中,在上层线程以参数的形式传到子线程!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值