У меня есть серверная часть Spring-Boot и интерфейс React (написанный на Typescript и использующий HTTP-клиент Axios). Каждое из этих приложений размещается в другом поддомене общего родительского домена.
Я пытаюсь использовать аутентификацию на основе файлов cookie для серверной части и сталкиваюсь со следующей проблемой:
- Запрос на вход выполняется интерфейсом, а сервер возвращает ответ с заголовком Set-Cookie.
- При запросах к серверной части в рамках одного и того же сеанса окна браузера (т. е. та же вкладка, отсутствие обновлений страницы и т. д.) браузер включает файл cookie, который был установлен на шаге 1.
- Если страница обновляется (или если к приложению пытаются получить доступ с отдельной вкладки), браузер не включает файлы cookie в запросы, сделанные внешним интерфейсом.
Больше контекста:
(с примерами URL)
- Серверная часть размещена по адресу 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 Headers:
Access-Control-Allow-Origin: https://ui.example.com
Access-Control-Allow-Credentials: true
Может ли кто-нибудь помочь мне понять, почему файл cookie не включается в запросы к серверной части после обновления страницы?
Редактировать
Вот код для настройки CORS и файлов cookie.
Внутренняя конфигурация 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);
}
});
};
}