記一次與Shiro有關的錯誤,404致使session丟失須要從新登陸

一 問題描述

前段時間上司忽然叫我幫忙解決老項目上的一個bug,出現的問題是不一樣用戶帳號,進入同一個頁面,有個別用戶刷新一下當前頁面就會重定向到登陸頁面,須要從新登陸。javascript

這是一個幾年前的一個項目,使用的是Srping + Spring MVC + Shiro + Jsp的項目,以前沒用過Shiro,因此對Shiro瞭解得很少。java

二 問題排查

打開項目源碼,先看進那個頁面前時都作了什麼處理。這是一個做品評審的頁面,因此在返回頁面前,分別把做品、評審規則、評委等數據put回了頁面。web

由於每一個用戶進入這個頁面不一樣的是那個做品List,因此我優先判斷是這裏出問題,因此先註釋掉,不把做品集合put回頁面,註釋掉後果真不會再出現從新刷新就會重定向到登陸頁面的問題。apache

接着我前往Jsp頁面查看,發現也只是一個簡單的for循環把做品集合輸出,沒毛病呀。bash

<c:forEach items="${worksFileVoList}" var="worksFileVo" varStatus="s">
    <li <c:if test="${s.count == 1}">class="on" data-uuid="${worksFileVo.fileId}"</c:if>><a href="javascript:void(0)" onclick="fileAction(this,'${worksFileVo.fileId}')"><img src="${pageContext.request.contextPath}/res/suffix/${worksFileVo.extension}.jpg"></a>
        <p class="word">${worksFileVo.fileName}</p></li>
</c:forEach>
複製代碼

最後我想,該不會是這個圖片的請求致使的吧,因而我又把img的src去掉,而後運行發現問題也不會出現了。cookie

我抱着好奇的心理,把代碼恢復運行,而後打開F12查看Cookie,發現這位有問題的帳號每次進入這個頁面時,他的JSESSIONID就會被刷新,而後才致使須要從新登陸。仔細觀察了一下,這個帳號,有個別做品的img是請求不到,是404,由於沒這個圖片,我補回了這張圖片,問題就解決了,但這是個治標不治本的辦法。session

爲何有個404請求,就致使要從新登陸了呢,難受呀,百思不得其解。jsp

三 解決問題

問題緣由和解決方法在這位老哥的集成Shiro後當遇到404錯誤時會丟失session文章中寫得很清楚了,這裏我複述一下。ui

1 首先若是登陸成功,Shiro的DefaultWebSessionManager會默認經過以下方式添加JSESSIONID Cookie到響應:this

private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
    if (currentId == null) {
        String msg = "sessionId cannot be null when persisting for subsequent requests.";
        throw new IllegalArgumentException(msg);
    } else {
        Cookie template = this.getSessionIdCookie();
        Cookie cookie = new SimpleCookie(template);
        String idString = currentId.toString();
        cookie.setValue(idString);
        cookie.saveTo(request, response);
        log.trace("Set session ID cookie for session with id {}", idString);
    }
}
複製代碼

2 若是客戶端訪問時會帶着個Cookie回來;可是注意:容器不認識的(Web容器並無真正建立HttpSession);Shiro默認狀況下會生成本身的一套Session,默認是MemorySessionDAO;即放到內存中的;和Web容器沒有任何關係;

3 接着訪問一個錯誤的頁面(如jsp);此時到了Shiro過濾器,過濾器經過;而後最後forward到這個錯誤頁面;你們應該知道默認狀況下jsp頁面是須要session的;因此此時jsp會調用request.getSession(),此時建立了一個Session;這會往Cookie寫JSESSIONID的。

解決方法:

一、換一個新的session key,如uid; 推薦這種作法;

二、錯誤頁面 設置<%@ page session="false' %>;

三、給shiro filter配置ERROR,而後在其filterChainDefinitions中添加/WEB-INF/jsp/error/error = anon;

我這裏使用第一種方法解決問題

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    
    <!-- 額外添加多的配置 -->
    <property name="sessionIdCookieEnabled" value="true"/>
    <property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>

<!-- 指定本系統SESSIONID, 默認爲: JSESSIONID 問題: 與SERVLET容器名衝突, 如JETTY, TOMCAT 等默認JSESSIONID,
        當跳出SHIRO SERVLET時如ERROR-PAGE容器會爲JSESSIONID從新分配值致使登陸會話丟失! -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg name="name" value="new.session.id"/>
</bean>
複製代碼

四 總結

本次排錯,雖然很快就找到了問題所在,可是最終在思考緣由時,由於對Shiro接觸得少,並無往這方面想,就是見識限制了本身的想象,望勤能補拙。

相關文章
相關標籤/搜索