前段時間上司忽然叫我幫忙解決老項目上的一個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接觸得少,並無往這方面想,就是見識限制了本身的想象,望勤能補拙。