问题描述
我有一个Spring-Boot后端和一个React前端(用Typescript编写并使用Axios HTTP客户端)。这些应用程序中的每一个都托管在公共父域的不同子域上。
我正在尝试对后端使用基于cookie的身份验证,并遇到以下问题:
- 前端发出登录请求,后端返回带有“ Set-Cookie”标头的响应。
- 在同一“浏览器窗口会话”(即同一标签,没有页面刷新等)中向后端发出的请求中,浏览器将包含在步骤1中设置的cookie。
- 如果刷新页面(或者尝试从单独的选项卡访问应用程序),则浏览器在前端发出的请求中不包含任何cookie。
更多上下文:
(带有示例网址)
- 后端托管在https://api.example.com
- 前端托管在https://ui.example.com
- “ Set-Cookie”标头如下所示:
EXAMPLE_SESSION_ID=55A66FFAB27931F115D9E6BA23A11EE4; Max-Age=7200; Expires=Sun,08-Nov-2020 23:53:39 GMT; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=None
- CORS标头:
-
Access-Control-Allow-Origin: https://ui.example.com
-
Access-Control-Allow-Credentials: true
-
有人可以帮我弄清楚为什么刷新页面后后端请求中没有包含cookie吗?
编辑
这是配置CORS和Cookies的代码。
后端CORS配置
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
corsConfiguration.setAllowedOrigins(getAllowedOrigins());
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedHeaders(
List.of(
"origin","content-type","accept","cookie","x-csrf-token"
)
);
corsConfiguration.setAllowedMethods(
List.of(
HttpMethod.OPTIONS.name(),HttpMethod.GET.name(),HttpMethod.POST.name(),HttpMethod.PUT.name(),HttpMethod.PATCH.name(),HttpMethod.DELETE.name()
)
);
UrlBasedCorsConfigurationSource corsConfigSource = new UrlBasedCorsConfigurationSource();
corsConfigSource.registerCorsConfiguration("/**",corsConfiguration);
return corsConfigSource;
}
后端Cookie自定义
@Getter
@Value("${my.custom.property.session.cookie.domain:}")
private String customPropertyCookieDomain;
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> stackOverflowExampleWebServerCustomizer() {
return factory -> {
factory.addContextCustomizers(customizer -> {
Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
cookieProcessor.setSameSiteCookies("None");
customizer.setCookieProcessor(cookieProcessor);
if (StringUtils.isNotBlank(customPropertyCookieDomain)) {
customizer.setSessionCookieDomain(customPropertyCookieDomain);
}
});
};
}
解决方法
在花了几个小时盯着Google Chrome浏览器的“网络”标签后,我决定看看如果尝试直接通过浏览器访问后端,我设置的cookie是否可以正常工作。果然,即使页面刷新并尝试在新选项卡中,cookie仍被一致发送。我做了一些挖掘,结果发现问题实际上与前端有关。刷新页面后,Axios HTTP客户端未设置withCredentials
标志。因为我的CORS配置将Access-Control-Allow-Credentials
设置为true,所以预检(OPTIONS)请求-响应与cookie不匹配,因此浏览器停止了将cookie追加到请求标头。
This answer解释了Axios问题的根本原因。
TLDR
当我在浏览器中刷新前端时,Axios不再设置withCredentials=true
。