window 刷新后,如何指示浏览器在请求中包含 cookie?
How do I instruct a browser to include a cookie in requests after the window has been refreshed?
我有一个 Spring-Boot back-end 和一个 React front-end(用 Typescript 编写并使用 Axios HTTP 客户端)。这些应用程序中的每一个都托管在一个公共 parent-domain.
的不同 sub-domain 上
我正在尝试对 back-end 和 运行 使用 cookie-based 身份验证以解决以下问题:
- 登录请求由 front-end 发出,back-end returns 响应为“Set-Cookie”header。
- 在同一“browser-window-session”(即同一选项卡、无页面刷新等)中对 back-end 发出的请求中,浏览器包含在步骤 1 中设置的 cookie。
- 如果刷新页面(或者如果尝试从单独的选项卡访问应用程序),浏览器不会在 front-end 发出的请求中包含任何 cookie。
更多上下文:
(带有示例 URL)
- back-end 位于 https://api.example.com
- front-end 位于 https://ui.example.com
- “Set-Cookie”header 看起来像这样:
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 Headers:
Access-Control-Allow-Origin: https://ui.example.com
Access-Control-Allow-Credentials: true
谁能帮我弄清楚为什么页面刷新后 back-end 的请求中没有包含 cookie?
编辑
这是配置 CORS 和 Cookie 的代码。
Back-End 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;
}
Back-End Cookie 自定义
@Getter
@Value("${my.custom.property.session.cookie.domain:}")
private String customPropertyCookieDomain;
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> WhosebugExampleWebServerCustomizer() {
return factory -> {
factory.addContextCustomizers(customizer -> {
Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
cookieProcessor.setSameSiteCookies("None");
customizer.setCookieProcessor(cookieProcessor);
if (StringUtils.isNotBlank(customPropertyCookieDomain)) {
customizer.setSessionCookieDomain(customPropertyCookieDomain);
}
});
};
}
在 Google Chrome 中盯着“网络”选项卡看了几个小时后,我决定看看如果我尝试访问 back-end 我设置的 cookie 是否有效直接通过浏览器。果然,即使使用 page-refreshes 并尝试在新选项卡中,cookie 也始终如一地发送。我做了一些挖掘,结果发现这个问题实际上与 front-end 有关。刷新页面后,Axios HTTP 客户端未设置 withCredentials
标志。因为我的 CORS 配置 Access-Control-Allow-Credentials
设置为 true,预检 (OPTIONS) request-response 与 cookie 不匹配,所以浏览器停止将 cookie 附加到请求 headers.
This answer解释了root-causeAxios的问题
TLDR
当我在浏览器中刷新 front-end 时,Axios 不再设置 withCredentials=true
。
我有一个 Spring-Boot back-end 和一个 React front-end(用 Typescript 编写并使用 Axios HTTP 客户端)。这些应用程序中的每一个都托管在一个公共 parent-domain.
的不同 sub-domain 上我正在尝试对 back-end 和 运行 使用 cookie-based 身份验证以解决以下问题:
- 登录请求由 front-end 发出,back-end returns 响应为“Set-Cookie”header。
- 在同一“browser-window-session”(即同一选项卡、无页面刷新等)中对 back-end 发出的请求中,浏览器包含在步骤 1 中设置的 cookie。
- 如果刷新页面(或者如果尝试从单独的选项卡访问应用程序),浏览器不会在 front-end 发出的请求中包含任何 cookie。
更多上下文:
(带有示例 URL)
- back-end 位于 https://api.example.com
- front-end 位于 https://ui.example.com
- “Set-Cookie”header 看起来像这样:
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 Headers:
Access-Control-Allow-Origin: https://ui.example.com
Access-Control-Allow-Credentials: true
谁能帮我弄清楚为什么页面刷新后 back-end 的请求中没有包含 cookie?
编辑
这是配置 CORS 和 Cookie 的代码。
Back-End 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;
}
Back-End Cookie 自定义
@Getter
@Value("${my.custom.property.session.cookie.domain:}")
private String customPropertyCookieDomain;
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> WhosebugExampleWebServerCustomizer() {
return factory -> {
factory.addContextCustomizers(customizer -> {
Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
cookieProcessor.setSameSiteCookies("None");
customizer.setCookieProcessor(cookieProcessor);
if (StringUtils.isNotBlank(customPropertyCookieDomain)) {
customizer.setSessionCookieDomain(customPropertyCookieDomain);
}
});
};
}
在 Google Chrome 中盯着“网络”选项卡看了几个小时后,我决定看看如果我尝试访问 back-end 我设置的 cookie 是否有效直接通过浏览器。果然,即使使用 page-refreshes 并尝试在新选项卡中,cookie 也始终如一地发送。我做了一些挖掘,结果发现这个问题实际上与 front-end 有关。刷新页面后,Axios HTTP 客户端未设置 withCredentials
标志。因为我的 CORS 配置 Access-Control-Allow-Credentials
设置为 true,预检 (OPTIONS) request-response 与 cookie 不匹配,所以浏览器停止将 cookie 附加到请求 headers.
This answer解释了root-causeAxios的问题
TLDR
当我在浏览器中刷新 front-end 时,Axios 不再设置 withCredentials=true
。