Spring Data Rest and Cors
Rozwijam aplikację Spring Boot z interfejsem Rest i frontem dart.
XMLHttpRequest wykonuje żądanie opcji, które jest obsługiwane całkowicie poprawnie. Po tym, ostateczne żądanie GET ("/products") jest wystawiane i nie powiodło się:
nie ma nagłówka 'Access-Control-Allow-Origin' na żądanym zasobie. Pochodzenie " http://localhost:63343 " nie jest zatem dozwolony dostęp.
Po pewnym debugowaniu znalazłem następujące:
Na AbstractHandlerMapping.konfiguracja corsConfiguration jest wypełniana dla wszystkich podklas z wyjątkiem RepositoryRestHandlerMapping. W RepositoryRestHandlerMapping nie jest obecna / ustawiona konfiguracja corsConfiguration podczas tworzenia, więc nie zostanie rozpoznana jako ścieżka / zasób cors.
= > No Cors headers attached
Czy to może być problem? Jak mogę to ustawić?
Klasy konfiguracji:
@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");
}
...
}
Próbowałem nawet ustawić Kors na adnotację:
@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false")
public interface ProductRepository extends CrudRepository<Product, String> {
}
Raw request nagłówki:
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
Surowe nagłówki odpowiedzi:
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
Używane wersje: Spring Boot 1.3.0M2 Wiosna 4.2.0.RC2
Czego mi brakuje?3 answers
Rzeczywiście, przed Spring Data REST 2.6 (Ingalls) tylko HandlerMapping
instancje utworzone przez Spring MVC WebMvcConfigurationSupport
i kontrolery oznaczone @CrossOrigin
były świadome CORS.
Ale teraz, gdy DATAREST-573 został naprawiony, RepositoryRestConfiguration
teraz wyświetla getCorsRegistry()
dla konfiguracji globalnej i @CrossOrigin
adnotacje w repozytoriach są również rozpoznawane, więc jest to zalecane podejście. Zobacz https://stackoverflow.com/a/42403956/1092077 odpowiedz na konkretne przykłady.
Dla ludzi, którzy muszą trzymać się Spring Data REST 2.5 (Hopper) lub poprzednie wersje, myślę, że najlepszym rozwiązaniem jest zastosowanie podejścia opartego na filtrach. Możesz oczywiście użyć Tomcat, Jetty lub ten , ale pamiętaj, że Spring Framework 4.2 zapewnia również CorsFilter
które używają tej samej logiki przetwarzania Kors, co @CrossOrigin
i addCorsMappings(CorsRegistry registry)
. Przechodząc przez UrlBasedCorsConfigurationSource
instancja do parametru konstruktora CorsFilter
, można łatwo uzyskać coś tak potężnego, jak natywne wsparcie Cors Spring global.
Jeśli używasz Spring Boot (który obsługuje Filter
fasolki), może to być coś w stylu:
@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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-22 08:24:43
Od Ingalls train został zrealizowany, wsparcie CORS w Spring Data jest teraz włączone. Istnieją dwa sposoby radzenia sobie z:
-
Adnotacja
@CrossOrigin
z określeniemorigins
,methods
, iallowedHeaders
przez interfejs@RepositoryRestResource
.@CrossOrigin(...) @RepositoryRestResource public interface PageRepository extends CrudRepository<Page, Long> { ... }
-
Konfiguracja globalna z
RepositoryRestConfiguration
wewnątrz klasy@Configuration
. Oznaczanie repozytoriów przez@CrossOrigin
nie jest wtedy konieczne.@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); } }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-26 20:03:43
Z jakiegoś powodu podejście zaproponowane w zaakceptowanej odpowiedzi powyżej nie działało dla mnie po aktualizacji Z Spring Boot 1.5.2 do 1.5.6.
Jak również zauważył komentarz @ BigDong, wyjątek, który dostałem, to:
Beaninstantationexception: nie udało się utworzyć instancji [javax.servlet.Filter]: Fabryczna metoda 'springSecurityFilterChain' wyrzuciła wyjątek; zagnieżdżonym wyjątkiem jest org.springframework.fasola.fabryka.BeanNotOfRequiredTypeException: Bean named 'corsFilter' is miał być typu " org.springframework.www.filtr.CorsFilter", ale faktycznie był typu " org.springframework.but.www.servlet.FilterRegistrationBean
Oto, co wymyśliłem, aby uzyskać "globalną" konfigurację CORS dla wszystkich punktów końcowych w naszym REST API, niezależnie od tego, czy są one zaimplementowane przy użyciu Spring Data Rest czy Spring MVC, z wszystkimi punktami końcowymi chronionymi przez Spring Security.
Nie byłem w stanie podłączyć CorsFilter
do potoku żądań w odpowiednim miejscu, więc zamiast tego skonfigurowałem SDR i MVC oddzielnie, jednak używając tej samej konfiguracji dla swoich CorsRegistry
za pomocą tego helpera:
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));
}
A następnie dla 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);
}
};
}
}
A następnie dla 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());
}
Oto kilka dalszych odniesień w temacie, które pomogły mi wymyślić tę odpowiedź:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-27 12:59:45