JHipster: CORS не работает при входе в систему (фактический запрос, а не предполетный)

Я хотел бы расширить мою монолитную настройку jHipster со вторым интерфейсным приложением, которое обращается к тому же API с другого URL-адреса. В качестве первого шага я включил CORS в application.yml, и я отправляю запрос из front-end с флагом withCredentials. Я использую сеансы и не проверяю JWT.

Многие методы работают сейчас, как ожидалось, но не все. Предполетный (OPTIONS запрос) всегда проходит и работает так, как ожидалось. Ответ этого вызова содержит правильные заголовки CORS.

Фактический запрос (например, запрос POST для входа), однако, требует также заголовка (Access-Control-Allow-Origin) в ответе. Этот заголовок автоматически устанавливается на мои пользовательские интерфейсы REST, но он не установлен в jHipster-генерируемых методах, таких как /api/authentication или /api/logout. Он также не работает с Spring ресурсами, защищенными безопасностью, такими как /api/account (только если он не вошел в систему, 401, после чего он работает так, как ожидалось, с правильными заголовками)

Что касается выхода из системы, например, Google Chrome реагирует со следующим сообщением на консоли, даже если вызов проходит через вкладку Сеть (POST статус ответа 200):

XMLHttpRequest не может загрузить http://localhost:8080/api/logout. В запрошенном ресурсе нет заголовка "Access-Control-Allow-Origin". Origin 'http://localhost:9000', следовательно, не допускается.

Мне было интересно, что я здесь делаю неправильно. Я думаю, что заголовки настроены неправильно. Теперь я могу вручную добавить заголовок (например, в AjaxAuthenticationSuccessHandler), но это кажется неправильным.

Я использую довольно устаревшую версию jHipster 3.7.0. Однако я бы предпочел не обновлять основной проект.

Есть ли у вас какие-либо идеи, что может быть причиной этой проблемы?



Заголовки

Вот полные заголовки вызова POST на /api/logout. Вызов OPTIONS работает так, как ожидалось, но в ответе POST заголовок Access-Control-Allow-Origin отсутствует:

OPTIONS Запрос

OPTIONS /api/logout HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:9000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Access-Control-Request-Headers: x-csrf-token
Accept: */*
DNT: 1
Referer: http://localhost:9000/
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,de-CH;q=0.2,it;q=0.2

Ответы

Ответ 1

Похоже, вы работаете в этой проблеме CORS, где один из фильтров перед CorsFilter в Spring цепях фильтра безопасности безопасности ошибка. Запрос никогда не достигает CorsFilter, в результате чего заголовки CORS отсутствуют в ответе. Поэтому Chrome жалуется на недостающие заголовки в консоли, даже если это другая ошибка.

Вам нужно поставить CorsFilter до CsrfFilter и UsernamePasswordAuthenticationFilter, чтобы при наличии какой-либо из этих фильтров ответ по-прежнему получал заголовки CORS. Для этого добавьте следующий код в SecurityConfiguration.java:

// import CorsFilter
import org.springframework.web.filter.CorsFilter;
...
...
// inject for JHipster v3 apps, add to constructor for JHipster v4 apps
@Inject
private CorsFilter corsFilter;
...
...
// add this line in the configure method before ".exceptionHandling()"
.addFilterBefore(corsFilter, CsrfFilter.class)

Также в SecurityConfiguration.java вы можете установить @EnableWebSecurity(debug = true), чтобы увидеть цепочку фильтров для каждого запроса. Вы можете убедиться, что все правильно, убедившись, что CorsFilter находится перед цепочкой CsrfFilter и UsernamePasswordAuthenticationFilter в цепочке:

Security filter chain: [
    WebAsyncManagerIntegrationFilter
    SecurityContextPersistenceFilter
    HeaderWriterFilter
    CorsFilter     <--------- Before CsrfFilter and UsernamePasswordAuthenticationFilter
    CsrfFilter
    CsrfCookieGeneratorFilter
    LogoutFilter
    UsernamePasswordAuthenticationFilter
    RequestCacheAwareFilter
    SecurityContextHolderAwareRequestFilter
    RememberMeAuthenticationFilter
    AnonymousAuthenticationFilter
    SessionManagementFilter
    ExceptionTranslationFilter
    FilterSecurityInterceptor
]

Если вы используете проблемы CSRF у своего нового клиента, вам может потребоваться сделать запрос GET после POST, чтобы обновить токен CSRF. Пример того, как JHipster обрабатывает это, можно увидеть при выходе из системы.

Ответ 2

Посмотрите, как org.springframework.web.cors.CorsConfiguration Spring bean настроен в общих свойствах приложения JHipster. Я думаю, что вам не хватает следующей строки конфигурации:

exposed-headers: "Authorization"

Я только что задокументировал это несколько часов назад, и также добавил эту конфигурацию по умолчанию несколько часов назад.

В следующем выпуске, который должен быть завтра, у вас должна быть новая страница Разделение интерфейсного и сервера API это должно объяснить, что лучше - и если вы нашли лучшее решение, не стесняйтесь улучшать эту страницу, это первая версия.