Chrome浏览器中请求无法携带Cookie的问题分析


问题背景

最近新做的一个内部管理系统要接入公司的统一登录。

接入流程如下:

  • 服务端接口增加拦截器,抓取请求携带的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不能设置为*

图片截取于https://developer.mozilla.org/

“改!”

@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

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):