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?

50
demandé sur Andrew Tobilko 2015-07-30 16:20:49

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;
    }
}
87
répondu Sébastien Deleuze 2017-06-22 08:24:43

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:

  1. L'annotation @CrossOrigin avec indication origins, methods, et allowedHeaders sur une interface @RepositoryRestResource.

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
  2. 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);
         }
    
    }
    
14
répondu Andrew Tobilko 2017-12-26 20:03:43

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:

6
répondu Johannes Rudolph 2017-08-27 12:59:45