一 问题描述
前段时间上司突然叫我帮忙解决老项目上的一个bug,出现的问题是不同用户账号,进入同一个页面,有个别用户刷新一下当前页面就会重定向到登录页面,需要重新登录。
这是一个几年前的一个项目,使用的是Srping + Spring MVC + Shiro + Jsp的项目,之前没用过Shiro,所以对Shiro了解得不多。
二 问题排查
打开项目源码,先看进那个页面前时都做了什么处理。这是一个作品评审的页面,所以在返回页面前,分别把作品、评审规则、评委等数据put回了页面。
因为每个用户进入这个页面不同的是那个作品List,所以我优先判断是这里出问题,所以先注释掉,不把作品集合put回页面,注释掉后果然不会再出现重新刷新就会重定向到登录页面的问题。
接着我前往Jsp页面查看,发现也只是一个简单的for循环把作品集合输出,没毛病呀。
forEach items="${worksFileVoList}" var="worksFileVo" varStatus="s">
if test="${s.count == 1}">class="on" data-uuid="${worksFileVo.fileId}" if>>"javascript:void(0)" onclick="fileAction(this,'${worksFileVo.fileId}')">"${pageContext.request.contextPath}/res/suffix/${worksFileVo.extension}.jpg">
"word">${worksFileVo.fileName}
forEach>
复制代码
最后我想,该不会是这个图片的请求导致的吧,于是我又把img的src去掉,然后运行发现问题也不会出现了。
我抱着好奇的心理,把代码恢复运行,然后打开F12查看Cookie,发现这位有问题的账号每次进入这个页面时,他的JSESSIONID就会被刷新,然后才导致需要重新登录。仔细观察了一下,这个账号,有个别作品的img是请求不到,是404,因为没这个图片,我补回了这张图片,问题就解决了,但这是个治标不治本的办法。
为什么有个404请求,就导致要重新登录了呢,难受呀,百思不得其解。
三 解决问题
问题原因和解决方法在这位老哥的集成Shiro后当遇到404错误时会丢失session文章中写得很清楚了,这里我复述一下。
1 首先如果登录成功,Shiro的DefaultWebSessionManager会默认通过如下方式添加JSESSIONID Cookie到响应:
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的。
解决方法:
1、换一个新的session key,如uid; 推荐这种做法;
2、错误页面 设置<%@ page session="false' %>;
3、给shiro filter配置ERROR,然后在其filterChainDefinitions中添加/WEB-INF/jsp/error/error = anon;
我这里使用第一种方法解决问题
"sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
"sessionIdCookieEnabled" value="true"/>
"sessionIdCookie" ref="sessionIdCookie"/>
"sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
"name" value="new.session.id"/>
复制代码
四 总结
本次排错,虽然很快就找到了问题所在,但是最终在思考原因时,因为对Shiro接触得少,并没有往这方面想,就是见识限制了自己的想象,望勤能补拙。