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());”

到此,問題被徹底解決!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章