web-dev-qa-db-fra.com

Problème de prise en charge de Global CORS: Spring Boot enable: seul GET fonctionne, POST, PUT et Delete ne fonctionnent pas

Mise à jour: Maintenant, en regardant en arrière plus d’un an plus tard, je donne une mise à jour qui espère pouvoir aider quelqu'un d’autre. 

Spring IO recommande d'utiliser la protection CSRF pour toute demande pouvant être traitée par un navigateur par des utilisateurs normaux. Si vous créez uniquement un service utilisé par des clients autres que les navigateurs, vous voudrez probablement désactiver la protection CSRF . Comme mon application est une API et sera traitée par un navigateur, la désactivation de CSRF n'est donc pas une approche.

CSRF étant activé avec Spring Boot par défaut, vous devez ajouter le code suivant pour ajouter un référentiel CSRF et un filtre pour ajouter le jeton CSRF à vos demandes http. (La solution vient d'ici Jeton CSRF non valide dans la demande POST )

@Override
protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/assets/**", "/templates/**", "/custom-fonts/**", "/api/profile/**", "/h2/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/login?logout")
                .permitAll()
                .and()
            .csrf().csrfTokenRepository(csrfTokenRepository())
                .and()
            .addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class); // Register csrf filter.
               }

La partie filtre et référentiel CsrfToken:

private Filter csrfHeaderFilter() {
    return new OncePerRequestFilter() {

        @Override
        protected void doFilterInternal(HttpServletRequest request,
                                        HttpServletResponse response,
                                        FilterChain filterChain) throws ServletException, IOException {

            CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
            if (csrf != null) {
                Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                String token = csrf.getToken();
                if (cookie == null || token != null
                        && !token.equals(cookie.getValue())) {

                    // Token is being added to the XSRF-TOKEN cookie.
                    cookie = new Cookie("XSRF-TOKEN", token);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                }
            }
            filterChain.doFilter(request, response);
        }
    };
}   


private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

Question originale que j'ai posée en février 2016

Je travaille sur l’établissement du support Global CORS pour une API RESTful avec Spring 4. 

Je suis le document officiel de démarrage de Spring ( https://spring.io/guides/gs/rest-service-cors/ ) et je l'ai ajouté à mon application:

public class SomeApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SomeApiApplication.class, args);
    }


    //Enable Global CORS support for the application
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:8080")
                        .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD")
                        .allowedHeaders("header1", "header2") //What is this for?
                        .allowCredentials(true);
            }
        };
    }
}

Je ne comprends pas pourquoi seul GET fonctionne. Pour le reste des appels http, je reçois un message d'erreur disant "Demande CORS non valide". Est-ce que quelque chose me manque dans la configuration? Si ma configuration n’est pas correcte, GET ne devrait pas fonctionner aussi bien. Je suis très confus. 

17
Half Ass Dev

J'ai eu le même problème - GET a travaillé. POST n'a pas. J'ai cherché une réponse dans le domaine CORS mais, finalement, j'ai découvert que c'était dû à la protection CSRF. Pour le résoudre, j'ai désactivé la protection CSRF dans la configuration de la sécurité: 

@Configuration @EnableWebSecurity
    public class SpringWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                **.csrf().disable()** //TODO: for production, must be reconfigured in order to disable only in specific cases. This line was added because without it, HTTP POST requests did not work. 
                .authorizeRequests()
                    .antMatchers("/api/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll();
        }

Assurez-vous de bien comprendre ce que vous faites: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html

8
iharel

Essayez de changer la méthode allowedOrigins en .allowedOrigins("*"). Postman est une extension qui s'exécute dans un autre "hôte".

Mais assurez-vous de bien comprendre les impacts: https://spring.io/understanding/CORS

5
Bruno

J'avais un problème similaire et j'ai compris que @CrossOrigin de mon contrôleur devait être supprimé pour résoudre le problème. Il reste cependant à comprendre pourquoi cela provoque une "demande CORS invalide".

2
Krisrettiwt

J'avais un problème similaire, seuls HEAD GET et POST travaillaient pour moi… .. J'ai découvert que addCorsMappings a une valeur par défaut pour allowedMethods .

Ce code fonctionne pour moi:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("*")
                        .allowedOrigins("http://localhost:4200");
            }
        };
    }
}
0
Charles