Spring Отдых и Корс
Я разрабатываю приложение загрузки Spring с интерфейсом Rest и выталкиванием дротиков.
XMLHttpRequest выполняет запрос OPTIONS, который обрабатывается полностью корректно. После этого выдается окончательный запрос GET ( "/products" ) и не выполняется:
Нет заголовка "Access-Control-Allow-Origin" присутствует на запрошенном ресурсе. Происхождение http://localhost:63343 ', следовательно, не допускается.
После некоторой отладки я нашел следующее:
Функция AbstractHandlerMapping.corsConfiguration заполняется для всех подклассов, кроме репозиторияRestHandlerMapping. В RepositoryRestHandlerMapping no corsConfiguration присутствует/задано во время создания и поэтому не будет распознаваться как путь/ресурс cors.
= > Нет заголовков CORS
Может ли это быть проблема? Как я могу установить его?
Конфигурационные классы:
@Configuration
public class RestConfiguration extends RepositoryRestMvcConfiguration {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowCredentials(false).allowedOrigins("*").allowedMethods("PUT", "POST", "GET", "OPTIONS", "DELETE").exposedHeaders("Authorization", "Content-Type");
}
...
}
Я даже попытался установить Cors для аннотации:
@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false")
public interface ProductRepository extends CrudRepository<Product, String> {
}
Заголовки необработанных запросов:
GET /products HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
authorization: Basic dXNlcjpwYXNzd29yZA==
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/43.0.2357.130 Chrome/43.0.2357.130 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:63343/inventory-web/web/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Заголовки исходного ответа:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 30 Jul 2015 15:58:03 GMT
Используемые версии:
Spring Загрузка 1.3.0.M2
Spring 4.2.0.RC2
Что мне не хватает?
Ответы
Ответ 1
Действительно, до Spring Data REST 2.6 (Ingalls) только HandlerMapping
экземпляры, созданные Spring MVC WebMvcConfigurationSupport
, а контроллеры, аннотированные с помощью @CrossOrigin
, были осведомлены о CORS.
Но теперь, когда DATAREST-573 исправлено, RepositoryRestConfiguration
теперь предоставляет getCorsRegistry()
для глобальной настройки и @CrossOrigin
аннотации на репозитории также признаны, поэтому это рекомендуемый подход. См. fooobar.com/questions/120072/... ответ для конкретных примеров.
Для людей, которым приходится придерживаться Spring Data REST 2.5 (Hopper) или предыдущих версий, я считаю, что лучшим решением является использование подхода на основе фильтра. Вы, очевидно, могли бы использовать Tomcat, Jetty или этот, но имейте в виду, что Spring Framework 4.2 также предоставляет CorsFilter
, которые используют ту же логику обработки CORS, что и подходы @CrossOrigin
и addCorsMappings(CorsRegistry registry)
. Передав экземпляр UrlBasedCorsConfigurationSource
в конструктор CorsFilter
, вы можете легко получить что-то столь же мощное, как Spring внутренняя глобальная поддержка CORS.
Если вы используете Spring Boot (который поддерживает Filter
beans), это может быть что-то вроде:
@Configuration
public class RestConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
Ответ 2
Так как был реализован поезд Ingalls, поддержка CORS в Spring Теперь данные. Есть два способа решения:
-
Аннотация @CrossOrigin
с указанием origins
, methods
и allowedHeaders
над интерфейсом @RepositoryRestResource
.
@CrossOrigin(...)
@RepositoryRestResource
public interface PageRepository extends CrudRepository<Page, Long> { ... }
-
Глобальная конфигурация с RepositoryRestConfiguration
внутри класса @Configuration
. Маркировка репозиториев с помощью @CrossOrigin
не требуется.
@Configuration
public class GlobalRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.getCorsRegistry()
.addMapping(CORS_BASE_PATTERN)
.allowedOrigins(ALLOWED_ORIGINS)
.allowedHeaders(ALLOWED_HEADERS)
.allowedMethods(ALLOWED_METHODS);
}
}
Ответ 3
По какой-то причине подход, предложенный в принятом ответе выше, не работал у меня после обновления с Spring Boot 1.5.2 до 1.5.6.
Как также отмечено комментарием @BigDong, исключение, которое я получил, было:
BeanInstantiationException: Не удалось создать экземпляр [javax.servlet.Filter]: Factory метод 'springSecurityFilterChain' сделал исключение; вложенное исключение - org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean с именем 'corsFilter', как ожидается, будет иметь тип 'org.springframework.web.filter.CorsFilter', но на самом деле имеет тип 'org.springframework.boot.web.servlet.FilterRegistrationBean
Итак, вот что я нашел, чтобы получить "глобальную" конфигурацию CORS для всех конечных точек в нашем REST API, независимо от того, реализованы ли они с помощью Spring Data Rest или Spring MVC, причем все конечные точки защищены Spring Безопасность.
Мне не удалось подключить CorsFilter
к конвейеру запроса в правой части, поэтому вместо этого я сконфигурировал SDR и MVC отдельно, однако используя эту конфигурацию для своих CorsRegistry
через этот помощник:
public static void applyFullCorsAllowedPolicy(CorsRegistry registry) {
registry.addMapping("/**") //
.allowedOrigins("*") //
.allowedMethods("OPTIONS", "HEAD", "GET", "PUT", "POST", "DELETE", "PATCH") //
.allowedHeaders("*") //
.exposedHeaders("WWW-Authenticate") //
.allowCredentials(true)
.maxAge(TimeUnit.DAYS.toSeconds(1));
}
И затем для MVC:
@Configuration
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class CustomWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// enables CORS as per
// https://docs.spring.io/spring-security/site/docs/current/reference/html/cors.html#cors
http.cors()
.and() // ...
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
applyFullCorsAllowedPolicy(registry);
}
};
}
}
И затем для SDR:
public class CustomRepositoryRestMvcConfiguration extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setReturnBodyOnCreate(true);
config.setReturnBodyForPutAndPost(true);
config.setReturnBodyOnUpdate(true);
config.setMaxPageSize(250);
config.setDefaultPageSize(50);
config.setDefaultMediaType(MediaTypes.HAL_JSON);
config.useHalAsDefaultJsonMediaType(true);
CustomWebSecurityConfiguration.applyFullCorsAllowedPolicy(config.getCorsRegistry());
}
Вот еще одна ссылка на эту тему, которая помогла мне придумать этот ответ: