bleau83
bleau83

Reputation: 515

Cors Error with Post mapping in Spring boot

I have a Spring boot application with a rest controller and an Angular application as frontend. For the moment they are both running in localhost and SpringSecurity is enabled is Spring. Originally I was unable the make a getRequest from Angular to Spring because of Cors. I added @CrossOrigin to my restContoller and now I'm able to do a Get request from angular to Spring. Now I have the same problem with post request. I want to send some form data from angular to Spring but I always get an error in Chrome. I added @CrossOrigin here as well but I still have the problem. If I try a post request with postmen it's working just fine

zone.js:3243 Access to XMLHttpRequest at 'localhost:8080/rest/contact' from origin 'http://localhost:4200' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

contact.component.ts:51 HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "localhost:8080/rest/contact", ok: false, …}

This is my security configuration:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void configure (AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
        .passwordEncoder(getPasswordEncoder());
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors();
        http
                .authorizeRequests()
                .antMatchers("/admin/**").authenticated()//.hasAnyRole("ADMIN","USER")
                .and().formLogin().loginPage("/login").permitAll()
                .and().logout();
        http.csrf().disable();
        //http.headers().frameOptions().disable();
    }


    private PasswordEncoder getPasswordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {

                return encode(charSequence).equals(s);
            }
        };
    }
}

My Cors configuration:

@Configuration
public class CorsConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

My rest controller:

@RestController()
@CrossOrigin(origins = "http://localhost:4200/**", maxAge = 3600)
public class GymRestController {

    private final GymRepository gymRepository;

    GymRestController (GymRepository gymRepository) {
        this.gymRepository = gymRepository;
    }

    @GetMapping("/rest/gyms")
    public List<Gym> findAll() {
        return gymRepository.findAll();
    }

    @PostMapping ("/rest/contact")
    public void submitContact(@RequestBody ContactForm contactForm) {
        System.out.println(contactForm);

    }
}

and my on submit method in angular

  onSubmit() {
    this.submitted = true;

    if (this.messageForm.invalid) {
        return;
    }

    this.success = true;

    this.contactModel.fromName = this.messageForm.get('name').value;
    this.contactModel.fromMail = this.messageForm.get('email').value;
    this.contactModel.subject = this.messageForm.get('subject').value;
    this.contactModel.message = this.messageForm.get('message').value;

    let url = "http://localhost:8080/rest/contact";
    // let url = "https://cors.io/?localhost:8080/rest/contact"
    this.http.post(url, this.contactModel).subscribe(
      res => console.log("success"),
      error => console.log(error),
      () => console.log("complete")
    );


  }

I've been trying for 3 days to get this working without any luck Any help would be appreciated

Upvotes: 5

Views: 9148

Answers (2)

bleau83
bleau83

Reputation: 515

I finally found the solution. I had to enable cors in Spring Security and disable csrf

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .cors().and()
            .authorizeRequests()
            .antMatchers("/admin/**").authenticated()//.hasAnyRole("ADMIN","USER")
            .and().formLogin().loginPage("/login").permitAll()
            .and().logout();
    http.csrf().disable();
    http.headers().frameOptions().disable();
}

I had to removed @CrossOrigin from the controller and I added the following configuration:

@Configuration
public class CorsConfiguration {

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

Upvotes: 5

Gunjan Kumar
Gunjan Kumar

Reputation: 677

Following on Spring io link : https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

If you are using Spring Boot, it is recommended to just declare a WebMvcConfigurer bean as following:

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

You can easily change any properties, as well as only apply this CORS configuration to a specific path pattern:

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
        .allowedOrigins("http://domain2.com")
        .allowedMethods("PUT", "DELETE","POST")
            .allowedHeaders("header1", "header2", "header3")
        .exposedHeaders("header1", "header2")
        .allowCredentials(false).maxAge(3600);
}

Above you can replace http://domain2.com with your localhost or required host/url.

Upvotes: 0

Related Questions