How I can fix broken CORS In Spring Boot + Vue app?

7.3k views Asked by At

In my problem I have Spring Boot Application (which is using Spotify API) on backend and Vue application on front. I use server on localhost:8080 and front on localhost:8081. I want to connect my frontend to my backend via axios and I try everything and still get CORS error.

When I call test GET endpoint /getList() I' ve got

Access to XMLHttpRequest at 'http://localhost:8080/getList' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

When I try to call POST /findTracks() I've got:

Access to XMLHttpRequest at 'http://localhost:8080/findTracks' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

And I alread tried everything (as you can see in the code below).

First:

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

@Configuration
@EnableWebMvc
public class CorsConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**").allowedHeaders("*").allowedMethods("*");
    } //even with .allowedOrgins("http://localhost:8081");
}

Then in Controller class:

@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class SpotifyApiController {

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @RequestMapping(value = "/getList", method = RequestMethod.GET)
    public List<String> getList() {
        ArrayList<String> a = new ArrayList<>();
        a.add("dwa");
        a.add("trzy");
        return a;
    }

    @RequestMapping(value = "/findTracks",
            method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json")
    public List<Track> getTracksForTitles(@RequestBody TrackWrapper userTracks, TrackService tracksService, OAuth2Authentication details) {
        return tracksService.generateTracksDetails(getActiveToken(details), userTracks);
    }

Then in Vue:

import axios from 'axios';
const SERVER_URL = 'http://localhost:8080'

const instance = axios.create({
    baseURL: SERVER_URL,
    timeout: 1000
});

export default{
    findTracksInSpotify:(jsonObject)=>instance.post('/findTracks',{
    userTracks: jsonObject.userTracks,
    headers:{
        'Content-Type': 'application/json',     
    }
}).then(() => function(data){
    return JSON.parse(data)
}),
getList:()=>instance.get('/getList',{
    transformResponse:[function(data){
        return JSON.parse(data)
    }]
}),
}

And my Spring Security class if needed:

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.context.request.RequestContextListener;


@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            .antMatcher("/**")
            .authorizeRequests()
            .antMatchers("/", "/login**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and().logout().logoutSuccessUrl("/").permitAll();
}
@Bean
public RequestContextListener requestContextListener() {
    return new RequestContextListener();
}
}

I even install chrome extension but it does not work either.

Can you tell me what I am doing wrong?

4

There are 4 answers

8
jccampanero On BEST ANSWER

I think that you do not need the class CorsConfiguration.

You do not need to annotate with CrossOrigin the SpotifyApiController either.

The configuration of CORS ideally should be placed in the security configuration. Something like that (in OAuth2Configuration):

import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
  // The configuration that you needed

  // If preflight requests are redirected by OAuth conf, you can try adding:
  // .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

  // CORS configuration

  // This value must be parameterized according to your application needs 
  final String corsOrigin="http://localhost:8081";
  // The idea is to insert the CORS filter before the filter injected by
  // the @EnableOAuth2Sso annotation
  http.addFilterBefore(new CorsFilter(corsConfigurationSource(corsOrigin)), AbstractPreAuthenticatedProcessingFilter.class);
}

private CorsConfigurationSource corsConfigurationSource(String corsOrigin) {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList(corsOrigin));
    configuration.setAllowedMethods(Arrays.asList("GET","POST","HEAD","OPTIONS","PUT","PATCH","DELETE"));
    configuration.setMaxAge(10L);
    configuration.setAllowCredentials(true);
    configuration.setAllowedHeaders(Arrays.asList("Accept","Access-Control-Request-Method","Access-Control-Request-Headers",
      "Accept-Language","Authorization","Content-Type","Request-Name","Request-Surname","Origin","X-Request-AppVersion",
      "X-Request-OsVersion", "X-Request-Device", "X-Requested-With"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}


1
Oktay Alizada On

There is a sample of RestConfiguration corsfilter. You can add the following bean to your code:

@CrossOrigin
@Configuration
public class RestConfiguration {

  @Bean
  public FilterRegistrationBean corsFilter() {

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");

    source.registerCorsConfiguration("/**", config);
    final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
  }
}
0
Santosh b On
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().configurationSource(request -> {
            CorsConfiguration cors = new CorsConfiguration();
            cors.setAllowedOrigins(
                    Lists.newArrayList("*"));
            cors.setAllowedMethods(Lists.newArrayList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
            cors.setAllowedHeaders(Lists.newArrayList("*"));
            return cors;
        }).and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("")
                .permitAll().and()
                .addFilterBefore(setLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
    }
0
Abhishek On

Did you try using @CrossOrigin(origins="http://localhost:8081") on your controller class and repository class?

Also in conjuction to it : Try to add WebConfigurer Bean in you main SpringBoot Application class and annonate that too with @CrossOrigin(origins="http://localhost:8081")

@Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                System.out.println("here");
                registry.addMapping("/**").allowedOrigins("http://localhost:8081").allowedMethods("PUT", "DELETE" )
                .allowedHeaders("header1", "header2", "header3")
                .exposedHeaders("header1", "header2")
                .allowCredentials(false).maxAge(3600);;
            }
        };
    }

Please visit this link too for enabling CORS in your application server side and check as per your configuration which CORS method you can use.