web-dev-qa-db-fra.com

Spring Data Rest et Cors

Je développe une application Spring Boot avec une interface Reste et une Dart en façade. 

XMLHttpRequest exécute une requête OPTIONS totalement gérée. 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. Origin ' http: // localhost: 63343 ' n'est donc pas autorisé à accéder.

Après quelques opérations de débogage, j’ai trouvé ce qui suit: Dans RepositoryRestHandlerMapping, aucune configuration cors n'est présente/définie au moment de la création et ne sera donc pas reconnue en tant que ressource/chemin cors.
=> Aucun en-tête CORS attaché
Est-ce que cela pourrait être le problème? Comment puis-je le définir? 

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 le Cors par annotation:

@CrossOrigin( methods = RequestMethod.GET, allowCredentials = "false")
public interface ProductRepository extends CrudRepository<Product, String> {


}

En-têtes de demande brute:

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 brutes:

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: Spring Boot 1.3.0.M2 Spring 4.2.0.RC2

Qu'est-ce qui me manque?

50
Thomas Letsch

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 compatibles CORS.

Mais maintenant que DATAREST-573 a été corrigé, RepositoryRestConfiguration expose maintenant une getCorsRegistry() pour la configuration globale et les annotations @CrossOrigin sur les référentiels sont également reconnues; il s'agit donc de l'approche recommandée. Voir https://stackoverflow.com/a/42403956/1092077 answer pour des exemples concrets.

Pour les personnes qui doivent s'en tenir à Spring Data REST 2.5 (Hopper) ou à des versions antérieures, la meilleure solution consiste à utiliser une approche basée sur le filtre. Vous pouvez évidemment utiliser Tomcat, Jetty ou celui-ci , mais sachez que Spring Framework 4.2 fournit également un CorsFilter qui utilise la même logique de traitement CORS que celle de @CrossOrigin et de addCorsMappings(CorsRegistry registry). En passant une UrlBasedCorsConfigurationSource instance au paramètre du constructeur CorsFilter, vous pouvez facilement obtenir quelque chose d'aussi puissant que la prise en charge globale de CORS native de Spring.

Si vous utilisez Spring Boot (qui prend en charge les beans Filter), cela peut ressembler à 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;
    }
}
89
Sébastien Deleuze

Depuis que le train Ingalls a été réalisé , le support de CORS dans Spring Data est maintenant disponible. Il y a deux façons de traiter:

  1. L'annotation @CrossOrigin avec la spécification de origins, methods et allowedHeaders sur une interface @RepositoryRestResource.

    @CrossOrigin(...)
    @RepositoryRestResource
    public interface PageRepository extends CrudRepository<Page, Long> { ... }
    
  2. Une configuration globale avec la RepositoryRestConfiguration dans une classe @Configuration. Le marquage des référentiels avec le @CrossOrigin n’est alors 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);
         }
    
    }
    
15
Andrew Tobilko

Pour une raison quelconque, l'approche suggérée dans la réponse acceptée ci-dessus ne fonctionnait pas 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: Echec de l'instanciation [javax.servlet.Filter]: La méthode d'usine 'springSecurityFilterChain' a lancé une exception; exception imbriquée est org.springframework.beans.factory.BeanNotOfRequiredTypeException: Un bean nommé 'corsFilter' devrait être de type 'org.springframework.web.filter.CorsFilter' mais était en fait de type 'org.springframework.boot.web.web. .servlet.FilterRegistrationBean

Voici donc ce que j'ai proposé pour obtenir une configuration CORS "globale" pour tous les points de terminaison de notre API REST, qu'ils soient implémentés avec Spring Data Rest ou Spring MVC, avec tous les points de terminaison protégés par Spring Security.

Je ne pouvais pas attacher une CorsFilter au pipeline de demandes au bon moment. J'ai donc configuré SDR et MVC séparément, mais en utilisant la même configuration pour leur CorsRegistry via cet assistant:

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 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());
}

Voici quelques références supplémentaires sur le sujet qui m'ont aidé à trouver cette réponse: 

7
Johannes Rudolph

J'essayais de frapper le service Spring Spring d'angular . Le projet Spring Spring est déployé sur le serveur Tomcat et angular est le serveur angulaire par défaut . suivre 

https://juristr.com/blog/2016/11/configure-proxy-api-angular-cli/

mais le problème persiste toujours ... Grâce à mon ancien 'Abbas bhai', il a suggéré d'ajouter une configuration dans le fichier de configuration du ressort pour éviter ce problème, j'ai donc ajouté ce code dans la configuration du printemps.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@ComponentScan("org.liferayasif.backend")
public class RestConfig extends WebMvcConfigurerAdapter{

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
        configurer.enable();
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
     * To avoid 'Access-Control-Allow-Origin'
     * Above error arising when I am hitting from angular to our rest service
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

}

Cette méthode a résolu mes cors "Access-Control-Allow-Origin".

@Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

Pour référence peut télécharger mon projet entier 

Mon lien URL github:

https://github.com/asifaftab87/SpringPersistenceHibernate

Direction générale - sécurité 

Projet - Modèle 

0
asifaftab87