在一台机器上安装两个Tomcat,在两个不同的Tomcat上部署了A和B两个项目,两个项目代码不相同。启动两个Tomcat后,使用同一个浏览器分别访问不同的Tomcat,出现sessionid(JSESSIONID)互相覆盖的情况。
如果A项目开启了CSRF防护,上面的sessionid覆盖就会导致操作A项目会出现“无法验证提供的CSRF令牌,因为找不到您的会话。”这个异常,新版本的Spring Security 不会帮你捕获这个异常,所以你可能在控制台什么都看不到,你可以在安全配置类自己捕获异常。
/*
* 安全配置类
* */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法安全设置
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*
* 自定义配置
* 主要配置路径,也就是资源的访问权限(是否需要认证,需要什么角色等)。
* */
@Override
protected void configure(HttpSecurity http) throws Exception {
//自定义捕获异常
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler();
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
System.out.println(accessDeniedException.getMessage());
String errorMessage="无法验证提供的CSRF令牌,因为找不到您的会话。解决办法:直接刷新页面可以获取会话";
Response response1 = new Response(false, errorMessage);
ServletOutputStream outputStream = response.getOutputStream();
String json = JSONObject.toJSONString(response1);
outputStream.write(json.getBytes());
}
}
}
上面只是你能看到异常了,但是异常主要信息是说“找不到你的会话”。别把注意力放在“无法验证提供的CSRF令牌”,不然你可能走弯路了。
自己打开控制台看项目B什么操作会引起JSESSIONID变化,那么就改这个操作,我的错误主要是controller返回一个重定向的操作,这就引起了JSESSIONID变化,所以项目A的JSESSIONID改变了,再次操作访问项目A就会出现“无法验证提供的CSRF令牌,因为找不到您的会话。”
**解决办法:**个人是取消重定向操作,只是返回需要访问的url给前台,由前端ajax再次发起请求,这样项目B就不会改变JSESSIONID了。
这样项目A和项目B共享的JSESSIONID就不会发生改变了,问题解决了。
一开始我以为CSRF过期了,然后用了各种方法来改,最后都搞不定,最后用以上的方法就解决问题了。
当然,有些人的问题和我的不太一样,如果也是“sessionid覆盖”问题的话,也可以参考
更改tomcat配置来解决sessionid覆盖问题
至于更改tomcat配置来解决sessionid覆盖,这个方法我没有试过,不确定有没有效果