netty整合shiro,报There is no session with id [xxxxxx]问题定位及解决

问题描述:

##### 在做netty和shiro整合测试时,程序启动并正常运行一段时间之后会发现shiro出现异常,异常信息为There is no session with id [xxxxxx]!重启之后可以恢复但是运行一会儿又会出现该情况,由于我这里没有使用shiro的web认证机制,网上一些解决类似此情况的方法无效。以下为我自己排查分析并解决的过程

第一步GC优化

dubugg模式下发现报错的地方为如下所示:

##### 从dubug模式发现,context此时的实例是DefaultSubjectContext实例,而createSubject方法中设置的三个属性值被封装到DefaultSubjectContext类的backingMap属性中,此时都还正常

private final Map<String, Object> backingMap;


public void setAuthenticated(boolean authc) {
        put(AUTHENTICATED, authc);
}

//put方法内容
public Object put(String s, Object o) {
        return backingMap.put(s, o);
}

##### 继续向下执行突然发现SubjectContext的值被清空了!也就是HashMap没了!由此最先怀疑的是shiro是否将hashMap公用了,然后被其他某个线程给干掉了,查看creatSubjectContext源码发现每次都会重新实例化一个SubjectContext类,因此我怀疑是给GC干掉了

protected SubjectContext createSubjectContext() {
        return new DefaultSubjectContext();
    }

##### 使用java自带的jvm分析程序,检查GC执行情况,截图如下,由于我没有进行jvm调优,导致GC执行频率非常高,每条能有好几次回收,因此可以确定是GC导致HashMap中的数据被回收,从而导致shiro认证失败,则优化GC即可

优化之后,HashMap中的值不再被GC回收,但是问题依然存在

第二步,根结所在

分析自己得代码加上网上查到得资料,原因应该是并发访问shiro导致shiro得session冲突导致,查看SecurityUtils.getSubject();源码发现shiro是从ThreadLocal中先获取Subject,如果Subject不存在则重新创建,这里有个问题,ThreadLocal在netty并发登录后会导致多个线程获取到同一个Subject实例,从而得到得sessionkey会与实际得sessionkey不一致从而抛出“There is no session with id”异常

//代码中获取Subject得方法
Subject sub = SecurityUtils.getSubject();
AuthenticationToken token = createJwtToken( ctx, msg);
sub.login(token);

// SecurityUtils.getSubject();对应源码

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

解决思路:

1. 在执行getSubject()方法之前,先执行ThreadContext.remove();方法,将当前shiro线程得TreadLocal缓存中缓存得Subjec实例删除,则每次执行login之前都重新创建Subject实例,则问题解决

2. 参考互联网大佬得解决方案:

将Subject sub = SecurityUtils.getSubject();获取Subject得方式改成“Subject sub = SecurityUtils.getSecurityManager().createSubject(new DefaultSubjectContext());”

到此,问题被彻底解决!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值