问题背景
最近新做的一个内部管理系统要接入公司的统一登录。
接入流程如下:
- 服务端接口增加拦截器,抓取请求携带的cookie。
- 服务端访问统一登录的校验接口,验证cookie的登录信息是否有效,无效则返回401。
- 前端页面收到401状态码,则跳转至统一登录页面。
问题描述
因为是前后端分离,且接口是统一走网关,所以前端发起的请求是跨域的。
“服务端跨域处理”
@Configuration
public class MyCorsConfiguration {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
“校验失败!”
Cookie依旧没有携带成功,经过查阅资料发现,如过Access-Control-Allow-Credentials
设置为true
,那么Access-Control-Allow-Origin
不能设置为*
“改!”
@Configuration
public class MyCorsConfiguration {
@Value("${e2.auth.acceptUrl}")
private String acceptUrl;
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin(acceptUrl);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
“这次想必是没问题了吧?”,“依旧失败!”
cookie就在浏览器里躺着,死活都不出现。
无奈之下求助百度,度娘说,谷歌浏览器升级了,跨域不允许携带Cookie。
既然Cookie不行,我 JS 读出来放到 header 里总行吧,结果。。。。
...
我换个Safari试了试,果然可以。
但是总不能不让用户使用谷歌浏览器啊,只好硬着头皮继续查问题。
果然皇天不负苦心人,在请求的Header里面发现了这一行
Sec-Fetch-Site: cross-site
原来始作俑者是它。
在一番查阅资料后,发现,原来是因为我请求页面的时候是HTTP,而请求接口的时候是HTTPS,所以谷歌浏览器默认带上了这个请求头,并且禁用了Cookie。
如果将Cookie的
Secure
设置为true
,且Samesite
属性设置为None
的话,也是可以成功携带的。
结论:
1. 跨域访问时,Chrome浏览器禁止跨协议的普通Cookie携带
2. 跨域携带认证信息,需要设置具体的Origin
解决方案:
1. 页面设置证书改为HTTPS访问
2. 服务端将Cookie的Secure
设置为true
,且Samesite
属性设置为None
网友评论