生活随笔
收集整理的這篇文章主要介紹了
关于shiro session失效报错问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近做了一個項目,要用到shiro,做完之后發現有個異常經常發生org.apache.shiro.session.UnknownSessionException: There is no session with id?,經過多天的研究,終于得以解決
登錄的時候異常信息:
[java]?view plain
?copy org.apache.shiro.session.UnknownSessionException:?There?is?no?session?with?id?[4e8fe40a-6347-4c53-b273-829889656f6e]?? ????at?org.apache.shiro.session.mgt.eis.AbstractSessionDAO.readSession(AbstractSessionDAO.java:170)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.DefaultSessionManager.retrieveSessionFromDataSource(DefaultSessionManager.java:236)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.DefaultSessionManager.retrieveSession(DefaultSessionManager.java:222)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.AbstractValidatingSessionManager.doGetSession(AbstractValidatingSessionManager.java:118)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.AbstractNativeSessionManager.lookupSession(AbstractNativeSessionManager.java:108)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.AbstractNativeSessionManager.lookupRequiredSession(AbstractNativeSessionManager.java:112)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.AbstractNativeSessionManager.getAttribute(AbstractNativeSessionManager.java:209)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.mgt.DelegatingSession.getAttribute(DelegatingSession.java:141)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.subject.support.DelegatingSubject.getRunAsPrincipalsStack(DelegatingSubject.java:469)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.subject.support.DelegatingSubject.getPrincipals(DelegatingSubject.java:153)[251:org.apache.shiro.core:1.2.3]?? ????at?org.apache.shiro.subject.support.DelegatingSubject.getPrincipal(DelegatingSubject.java:149)[251:org.apache.shiro.core:1.2.3]??
為何找不到呢,原因是這樣的。
當用戶登錄的時候,web容器tomcat或者jetty會在線程池里面啟用線程調度,線程里面找到對應的servlet,shiro登錄的時候代碼如下
[java]?view plain
?copy <span?style="white-space:pre">????</span>Subject?currentUser?=?SecurityUtils.getSubject();?? ?????????? ????????String?sessionId?=?"";?? ?? ????????if?(!currentUser.isAuthenticated())?{?? ??????????????UsernamePasswordToken?token?=?new?UsernamePasswordToken(username,?DigestUtils.md5Hex(passwd));?? ??????????????token.setRememberMe(true);?? ??????????????currentUser.login(token);?? ?????????}??
方法SecurityUtils.getSubject()源碼是這樣
[java]?view plain
?copy public?static?Subject?getSubject()?{?? ????????Subject?subject?=?ThreadContext.getSubject();?? ????????if?(subject?==?null)?{?? ????????????subject?=?(new?Subject.Builder()).buildSubject();?? ????????????ThreadContext.bind(subject);?? ????????}?? ????????return?subject;?? }??
我們清楚的看到subject是從ThreadContext獲取,創建過就直接從里面獲取,沒有創建的話就重新創建一個subject,然后綁定到ThreadContext,調用subject獲取session的時候,他會去創建一個session,并且把session緩存起來,操作方法是在AbstractSessionDAO類里面,跟蹤得知這里放的是subject的代理對象。如果session超時時間設置過短的話,在用戶登錄的時候,隨著web容器分配的線程,很大的機會會分配之前的線程,而之前的線程綁定過了subject,subject沒有失效,subejct對象里面的session也沒有什么問題,但是session緩存里面的session失效了,用戶登錄的時候執行到currentuser.login(token)這個方法,他拿著之前的session,那后要去緩存里面讀取,但是已經失效了,所以會報上面那個異常。
問題就是出現在這里,subject綁定到thread上下文里面,subject對象的session是個代理對象,正真的session是放在緩存里面,web容器隨機分配的線程有可能綁定過subject,一旦session失效,就會報錯。
解決的辦法是在shiro去讀取session之前判斷有沒有失效,如果失效移除ThreadContext里面的subject,并且刪除緩存里面的session,代碼如下
[java]?view plain
?copy @Override?? ????public?String?login(String?username,?String?passwd)?{?? ?????????? ????????Subject?currentUser?=?SecurityUtils.getSubject();?? ?????????? ?? ????????if((System.currentTimeMillis()-currentUser.getSession().getStartTimestamp().getTime())>=lengthenTimeOut-1000){?? ????????????ThreadContext.remove(ThreadContext.SUBJECT_KEY);?? ????????????shiroSessionManager.getSessionDAO().delete(currentUser.getSession());?? ????????????currentUser?=?SecurityUtils.getSubject();?? ????????}?? ?????????? ????????String?sessionId?=?"";??
[java]?view plain
?copy ????try?{?? ????????if?(!currentUser.isAuthenticated())?{?? ????????????UsernamePasswordToken?token?=?new?UsernamePasswordToken(username,?DigestUtils.md5Hex(passwd));?? ????????????token.setRememberMe(true);?? ????????????currentUser.login(token);?? ????????}?? ????????? ????????sessionId?=?currentUser.getSession().getId().toString();?? ?????????? ?? ????}?catch?(ExcessiveAttemptsException?ex)?{?? ????????log.info(username?+?"帳號被鎖定1小時!",?ex);?? ????}?catch?(UnknownAccountException?uae)?{?? ????????log.info(username?+?"賬戶不存在!",?uae);?? ????}?catch?(IncorrectCredentialsException?ice)?{?? ????????log.info(username?+?"密碼不正確!",?ice);?? ????}?catch?(LockedAccountException?lae)?{?? ????????log.info(username?+?"賬戶被禁了!",?lae);?? ????}?catch?(AuthenticationException?ae)?{?? ????????log.info(username?+?"用戶名或密碼錯誤!",?ae);?? ????}?catch?(UnknownSessionException?ue)?{?? ????????log.info("登錄session失效"?+?sessionId,?ue);?? ?????????? ????}?? ?? ????log.info("登錄成功返回的sessionId+++++++++++++"?+?sessionId);?? ????return?sessionId;?? }??
總結
以上是生活随笔為你收集整理的关于shiro session失效报错问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。