Spring Data Rest et Cors
Je développe une application Spring Boot avec une interface Rest et une dart fronted.
Le XMLHttpRequest exécute une requête D'OPTIONS qui est traitée totalement correcte. Après cela, la demande finale GET ("/products") est émise et échoue:
aucun en-tête' Access-Control-Allow-Origin ' n'est présent sur la ressource demandée. Origine 'http://localhost:63343' n'est donc pas autorisé à accéder.
Après un certain débogage, j'ai trouvé ce qui suit:
Le AbstractHandlerMapping.corsConfiguration est renseignée pour toutes les sous-classes sauf RepositoryRestHandlerMapping. Dans le RepositoryRestHandlerMapping, aucune corsConfiguration n'est présente / définie au moment de la création et ne sera donc pas reconnue comme chemin / ressource cors.
= > Aucun en-tête CORS attaché
Pourrait-il être le problème? Comment puis-je le mettre?
Classes de Configuration:
@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");
}
...
}
J'ai même essayé de définir les Cors par annotation:
@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false")
public interface ProductRepository extends CrudRepository<Product, String> {
}
Demande brute en-têtes:
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
En-têtes de réponse bruts:
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
Versions utilisées: Botte À Ressort 1.3.0.M2 Printemps version 4.2.0.RC2
, Que dois-je manquer?
3 réponses
En effet, avant Spring Data REST 2.6 (Ingalls), seules les instances HandlerMapping
créées par Spring MVC WebMvcConfigurationSupport
et les contrôleurs annotés avec @CrossOrigin
étaient conscients de CORS.
Mais maintenant que DATAREST-573 a été corrigé, RepositoryRestConfiguration
expose maintenant un getCorsRegistry()
pour la configuration globale et les annotations @CrossOrigin
sur les dépôts sont également reconnues, c'est donc l'approche recommandée. Voir https://stackoverflow.com/a/42403956/1092077 réponse pour des exemples concrets.
Pour les gens qui doivent s'en tenir à Spring Data REST 2.5 (Hopper) ou versions précédentes, je pense que la meilleure solution est d'utiliser une approche basée sur un filtre. Vous pouvez évidemment utiliser Tomcat, Jetty ou celui-ci , mais sachez que Spring Framework 4.2 fournit également un CorsFilter
qui utilisent la même logique de traitement CORS que les approches @CrossOrigin
et addCorsMappings(CorsRegistry registry)
. En passant un UrlBasedCorsConfigurationSource
instance au paramètre constructeur CorsFilter
, vous pouvez facilement obtenir quelque chose d'aussi puissant que le support global cors natif de Spring.
Si vous utilisez Spring Boot (qui prend en charge Filter
beans), cela pourrait être quelque chose comme:
@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;
}
}
Depuis que Le Train Ingalls a été réalisé , le support de CORS dans les données de printemps est maintenant activé. Il y a deux façons de traiter:
-
L'annotation
@CrossOrigin
avec indicationorigins
,methods
, etallowedHeaders
sur une interface@RepositoryRestResource
.@CrossOrigin(...) @RepositoryRestResource public interface PageRepository extends CrudRepository<Page, Long> { ... }
-
Une configuration globale avec le
RepositoryRestConfiguration
dans une classe@Configuration
. Le marquage des référentiels par le@CrossOrigin
n'est donc pas nécessaire.@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); } }
Pour une raison quelconque, l'approche suggérée dans la réponse acceptée ci-dessus n'a pas fonctionné pour moi après la mise à niveau de Spring Boot 1.5.2 à 1.5.6.
Comme l'a également souligné le commentaire de @BigDong, l'exception que j'ai eue était:
BeanInstantiationException: échec de l'instanciation de [javax.servlet.Filter]: la méthode D'usine 'springSecurityFilterChain' a jeté l'exception; l'exception imbriquée est org.springframework.haricot.usine.BeanNotOfRequiredTypeException: Bean nommé 'corsFilter' est prévu pour être de type 'org.springframework.Web.filtrer.CorsFilter 'mais était en fait de type' org.springframework.démarrage.Web.servlet.FilterRegistrationBean
Voici donc ce que j'ai trouvé pour obtenir une configuration CORS "globale" pour tous les points de terminaison de notre API REST, qu'ils soient implémentés en utilisant Spring Data Rest ou Spring MVC, avec tous les points de terminaison protégés par Spring Security.
Je n'ai pas pu accrocher un CorsFilter
dans le pipeline de requêtes au bon point, donc à la place j'ai configuré SDR et MVC séparément, cependant en utilisant la même configuration pour leur CorsRegistry
via cette aide:
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));
}
Et puis pour 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);
}
};
}
}
Et puis pour DTS:
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());
}
Voici quelques autres références sur le sujet qui m'ont aidé à trouver cette réponse: