Spring Boot : CORS Issue

32,203

Solution 1

Although Spring security provides a way to configure CORS in http configurer, there's a much cleaner approach to add CORS filter to the application-

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCORSFilter implements Filter {


@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}

}

Ordering the filter with highest precedence makes sure that MyCORSFilter implementation of javax.servlet.Filter is the first one in the chain. Hope this helps

Solution 2

Checkout this guide from Spring:

https://spring.io/guides/gs/rest-service-cors/

There are few ways to add CORS support in Spring Boot.

Using global configuration:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
        }
    };
}

And using @CrossOrigin annotation:

@CrossOrigin(origins = "http://localhost:9000")
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
    System.out.println("==== in greeting ====");
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
}

Solution 3

There is no need of adding any additional Filters or WebMvcConfigurer. The main problem is 'Access-Control-Allow-Origin' does not present in the header because corsConfigurationSource does not add the necessary configuration to get the relevant CORS response headers. Hence, the below missing configurations have to be added when we configure CorsConfigurationSource

configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");

We have to configure cors CorsConfigurationSource as below

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .cors().configurationSource(corsConfigurationSource())
                .and()
                 .....
  }

 @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowCredentials(true);
        //the below three lines will add the relevant CORS response headers
        configuration.addAllowedOrigin("*");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

If anyone facing CORS issue with Spring Boot 2.4.0 plus versions when having the following combination then refer to answer

CorsConfigurationSource#setAllowedOrigins value as *

and

CorsConfigurationSource#setAllowCredentials value as true

Solution 4

Ok, so I realized that it was deprecated. If you look on baeldung it has how to do it the new way since they updated webmvcconfigurer:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("*").allowedOrigins(frontDomain);
    }
}
Share:
32,203
Mohit Kanwar
Author by

Mohit Kanwar

An enthusiastic developer who loves to design and program applications for Internet.

Updated on July 09, 2022

Comments

  • Mohit Kanwar
    Mohit Kanwar almost 2 years

    I am using Spring Boot version 2.0.2Release. Below is my security configuration

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(
            prePostEnabled = true,
            securedEnabled = true,
            jsr250Enabled = true)
    @ComponentScan("com.mk")
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private AuthenticationProvider myAuthenticationProvider;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http.cors().configurationSource(corsConfigurationSource())
                    .and()
                    .csrf().disable()
                    .anonymous().and()
                    .authorizeRequests()
                    .antMatchers(HttpMethod.GET,"/index.html").permitAll()
                    .antMatchers(HttpMethod.POST,"/login").permitAll()
                    .antMatchers(HttpMethod.GET,"*").authenticated()
                    .and().httpBasic();
        }
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("*"));
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            configuration.setAllowCredentials(true);
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }
    

    I am unable to invoke any API (including login which is permitAll) because of CORS issue.

    On Browser I am getting (It works with Postman, since CORS check is not made there)

    Failed to load http://localhost:8080/myurl: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.

  • Paulo van Goethe
    Paulo van Goethe almost 6 years
    You don't have to use @EnableWebMvc I don't think . If you have that, spring boot won't auto configure the mvc.
  • Paulo van Goethe
    Paulo van Goethe almost 6 years
    Also, what's the point of cors if you are going to allow all origins which is what your code says.
  • Mohit Kanwar
    Mohit Kanwar almost 6 years
    You are correct regarding allowing all origins, this is a sample code that I am using for testing.
  • Mohit Kanwar
    Mohit Kanwar almost 6 years
    This one works for me. with the only issue being that this is being invoked multiple times in same request.
  • Paulo van Goethe
    Paulo van Goethe almost 6 years
    Ok, I figured something like that was going on.
  • priteshbaviskar
    priteshbaviskar almost 6 years
    It can be the case that it is called for every single request made by browser apart from your api call. For eg. css, icons, images etc.
  • Mohit Kanwar
    Mohit Kanwar almost 6 years
    not the css/icons etc because they are hosted on different server, but let me check
  • The Dnino
    The Dnino over 5 years
    @MohitKanwar Try to use OncePerRequestFilter , public class CustomFIlter extends OncePerRequestFilter
  • Tomas Lukac
    Tomas Lukac over 4 years
    This didn't work for me, but this did: stackoverflow.com/a/36821971/8092044
  • GalAbra
    GalAbra about 3 years
    Why do you addAllowedOrigin("*") after you've setAllowedOrigins(Arrays.asList("*"))?
  • Prasanth Rajendran
    Prasanth Rajendran about 3 years
    yes, you can remove the following addAllowedOrigin("*") as we have already added setAllowedOrigins(Arrays.asList("*")), I added just to illustrate multiple option is possible to add the origins
  • JSON derulo
    JSON derulo almost 3 years
    But if you remove these duplicate lines then it's the same code as in OP's question, no? I don't get it, I have my config like you said, but still preflight has "No Allow Origin Header"...