一、背景
在微服务中,为了实现Session共享,使用Spring Session框架将sesion信息存储到redis中,并自动进行序列化与反序列化。但是在前端的请求中,却发现无法使用Session,Session中获取的内容得不到
二、猜想与解决
-
初步判断两个请求的Session不是同一个,通过wireshark进行抓包,发现每次请求都没有带Cookie,同时服务器每次都使用Set-Cookie设置SESSION,同时带有了很多奇怪的Cookie属性
-
记忆中,以往传递SessionId都是通过JSESSIONID的Cookie,但这里服务器要求设置的却是SESSION,猜测Spring Session自定义了SessionId策略,然后对Cookie的那些参数进行了查询,具体意思如下:
- httpOnly:防止XSS攻击,使得JS无法获取该Cookie
- SameSite: 用于限制第三方网站请求携带Cookie的策略,具体可参考这里
- Path: 访问该网站相同应用上下文时带上改Cookie,相当于指定ContextPath
-
根据以上查询,基本判断是因为更换的Cookie名称和httpOnly导致axios无法带上该Cookie来使用Session,于是查找Spring Session对Cookie中SessionId的读写,具体参考这里,于是知道是org.springframework.session.web.http.CookieSerializer接口负责,默认实现是org.springframework.session.web.http.DefaultCookieSerializer
//org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration
@PostConstruct
public void init() {
CookieSerializer cookieSerializer = (this.cookieSerializer != null) ? this.cookieSerializer
: createDefaultCookieSerializer();
this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
}
@Autowired(required = false)
public void setCookieSerializer(CookieSerializer cookieSerializer) {
this.cookieSerializer = cookieSerializer;
}
- 由此代码可知,只需自定义一个CookieSerializer即可注入到该配置中替换默认配置,同时发现DefaultCookieSerializer提供属性设置,于是改法如下:
@Configuration
@EnableRedisHttpSession
public class MySessionAutoConfiguration {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setSameSite(null);
// 重点在下面两个方法的调用,我将名字改为默认的JSESSIONID同时禁用HttpOnly
serializer.setUseHttpOnlyCookie(false);
serializer.setCookieName("JSESSIONID");
serializer.setDomainName(null);
return serializer;
}
}
- 问题完美解决
三、axios跨域注意
- 若跨域时需要带上cookie,则需手动设置withCredentials=true
// 全局设置可以如下
import axios from "axios"
axios.defaults.withCredentials
// 如果是部分设置,则只需要在config中带上改属性即可,如
axios.get("/user/login",{withCredentials:true})
- 前端使用了withCredentials=true,则后端要进行允许,如下:
// 以下是Http响应头
Access-Control-Allow-Origin: localhost:8080 //这里需要是具体的请求传递过去的Origin头,不能是*
Access-Control-Allow-Credentials: true // 开启这里才能带上Cookie
四、参考
1.Cookie 的 SameSite 属性
2. SpringSession系列-sessionId解析和Cookie读写策略
3. Cookie中的httponly的属性和作用