Spring boot enable Global CORS support issue: only GET is working, POST, PUT and Delete are not working

39,861

Solution 1

I had a a similar issue, only HEAD GET and POST were working for me. I found out that addCorsMappings has a default value for allowedMethods.

This code works for me:

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

Solution 2

I had the same problem - GET worked. POST didn't. I looked for an answer in the CORS domain but eventually, found that it was due to CSRF protection. To solve it, I disabled CSRF protection in the security configuration:

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

Make sure you understand what you're doing: https://docs.spring.io/spring-security/site/docs/current/reference/html/web-app-security.html#csrf

Solution 3

Try to change allowedOrigins method to .allowedOrigins("*"). Postman is an extension and it runs in another "host".

But make sure that you understand the impacts: https://spring.io/understanding/CORS

Solution 4

I faced the same issue and after doing research what i found is, the browser looks for an HTTP header named Access-Control-Allow-Origin in the response.

The browser sends an OPTION request to find out what methods like PUTs, DELETE are allowed. If the requested method is allowed from server side, then the browser will make the actual request, again passing or blocking the response depending on the Access-Control-Allow-Origin header in the response. Simply add a spring bean, that will solve your problem.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class RestConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

Share:
39,861
Half Ass Dev
Author by

Half Ass Dev

Updated on December 17, 2021

Comments

  • Half Ass Dev
    Half Ass Dev over 2 years

    Update: Now looking back more than a year later, I am giving an update hope that will help someone else.

    Spring IO recommend using CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection. Since my app is an API and will be processed by a browser, so disable CSRF is not an approach.

    CSRF is enabled with Spring Boot by default, you would need to add the following code to add a CSRF repository and a filter to add the CSRF token to your http requests. (The solution comes from here Invalid CSRF Token in POST request )

    @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.
                   }
    

    The filter & CsrfToken Repository part:

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

    Original Question I asked back in Feb 2016

    I working on enabeing the Global CORS support for a Spring-boot RESTful API with Spring 4.

    I am following the official Spring Boot Doc(https://spring.io/guides/gs/rest-service-cors/) and have added this to my 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);
                }
            };
        }
    }
    

    I don't get why only GET is working, for the rest of http calls, I am getting an error message saying "Invalid CORS request". Do I miss anything in the set up? If my set up is not right, GET should not work as well. I am very confussed.