自定义shiro过滤器没有Set Cookie问题。
比如我们通常会针对ajax的请求,返回json数据,一般的实现大概是这样。
public class MyUserFilter extends UserFilter {
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestedWith = request.getHeader("X-Requested-With");
Subject subject = SecurityUtils.getSubject();
if (!subject.isRemembered() && !subject.isAuthenticated() && StringUtils.isNotEmpty(requestedWith)
&& StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax返回指定数据
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(JSONObject.toJSONString(ResultBean.noLogin("请先登录")));
return false;
} else {//不是ajax进行重定向处理
return super.onAccessDenied(request, response);
}
}
}
这个基本满足了ajax请求的拦截后返回json的需求,但是引起了一个非常怪的问题,非登录用户,网站在响应的时候没有Set Cookie的动作(清理缓存后,这个问题百分百重现),也就是在后台会产生这样一个问题:每次非登录用户的sessionId一直在变
,前端的请求没有相应的JSESSIONID
(自定义的名称)。
先上解决方法,在return false之前执行saveRequest(request)
,即:
if (!subject.isRemembered() && !subject.isAuthenticated() && StringUtils.isNotEmpty(requestedWith)
&& StringUtils.equals(requestedWith, "XMLHttpRequest")) {//如果是ajax返回指定数据
// 省略,同上
super.saveRequest(request);
return false;
} else {//不是ajax进行重定向处理
return super.onAccessDenied(request, response);
}
解决过程:
我反复找原因,反复对比,发现问题就是出在自定义的过滤器这里。
网上找了一大圈,竟然都没有相关的回答,我只能去参考shiro的UserFilter
,查看了AccessControlFilter
中的
protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
saveRequest(request);
redirectToLogin(request, response);
}
发现它是有一个saveRequest
操作,代码如下:
public static void saveRequest(ServletRequest request) {
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
HttpServletRequest httpRequest = toHttp(request);
SavedRequest savedRequest = new SavedRequest(httpRequest);
session.setAttribute(SAVED_REQUEST_KEY, savedRequest);
}
可以明显地看到,它是有个session key的设置动作的。
像在我自己实现的onAccessDenied
中,return false前没有保存动作,那么JSESSIONID
就不会保存,然后这个JSESSIONID
大概会在哪里被清空,并且不会再response,那么之后在登录之前,前端都不会有这个id,
所以在return false之前加上saveRequest(request)
,可以解决前端没有JSESSIONID
的问题。