18

I am getting 'Invalid CORS request' when I try to PutMapping of my API in Postman. But it is working fine for 'POST' and 'GET' mapping.

Why is it not working for the 'PUT' operation?

My Spring Boot version: 2.0

This is my config:

@Override
protected void configure(HttpSecurity http) throws Exception {




    http.cors().and().csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/h2-console/**/**").permitAll()
            .antMatchers(HttpMethod.GET,"/user/get-request").permitAll()
            .antMatchers(HttpMethod.POST,"/user/post-request").permitAll()
            .antMatchers(HttpMethod.PUT,"/user/put-request").permitAll()
            .and()
            .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
            .and()
            .addFilter(new JwtAuthenticationFilter(authenticationManager()))
            .addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtUserDetailService));




}


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

            }
        };
    }

This is my controller :

@RestController
@RequestMapping("/user")
public class UserController {

@PutMapping("/put-request")
public void doResetPassword(@RequestBody String password) {
    System.out.println("PUT MAPPING");


}

@PostMapping("/post-request")
public void doResetPassword(@RequestBody String password) {
    System.out.println("POST MAPPING");


}

@GetMapping("/get-request")
public void doResetPassword() {
    System.out.println("GET MAPPING");


}

}
Samet Baskıcı
  • 1,090
  • 3
  • 13
  • 26

6 Answers6

18
@Configuration
public class CrossOriginConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry
                        .addMapping("/**")
                        .allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS");
            }
        };
    }

}
Rares Oltean
  • 606
  • 6
  • 14
9
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    final CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(ImmutableList.of("*"));
    configuration.setAllowedMethods(ImmutableList.of("HEAD",
            "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
    configuration.setAllowCredentials(true);
    configuration.setAllowedHeaders(ImmutableList.of("*"));
    configuration.setExposedHeaders(ImmutableList.of("X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

I managed to allow cors request by adding this bean. You can configure setAllowedHeaders() and setExposedHeaders() by your need.

Also, I added this line to my controller;

@RequestMapping(value = "/auth")
@RestController
@CrossOrigin(origins = "*") //this line
public class AuthenticationController {..}

If your controller needs to handle on-the-fly OPTION request you can add this method to your controller. You can configure the value by your endpoint.

@RequestMapping(value = "/**/**",method = RequestMethod.OPTIONS)
public ResponseEntity handle() {
    return new ResponseEntity(HttpStatus.OK);
}
Y.Kaan Yılmaz
  • 612
  • 5
  • 18
  • hanks, this annotation solve the problem **'@CrossOrigin(origins = "*")'** , but I am confused that why we need it, we already specified origins in config class. – Samet Baskıcı Mar 17 '18 at 14:21
  • i have one more question about this annotation : '@RequestMapping(value = "/**/**",method = RequestMethod.OPTIONS)'** , what kind of scenario is it working for? – Samet Baskıcı Mar 17 '18 at 14:31
  • I'm not an expert but I think we need to map which endpoints allow cross-origin requests. So, that's why we need to put the @CrossOrigin annotation on controllers. Hope someone with a proper knowledge can explain it. – Y.Kaan Yılmaz Mar 17 '18 at 14:33
  • for your second question, take a look at this https://stackoverflow.com/questions/12569308/spring-difference-of-and-with-regards-to-paths – Y.Kaan Yılmaz Mar 17 '18 at 14:34
  • i know it will handle all Option request but in which stuations we need it ? – Samet Baskıcı Mar 17 '18 at 14:40
  • I'm using angular (ionic) as a front end and it sends pre-option request to verify the server is running. So, when I make a post request from application, it sends a option request just before the real request. – Y.Kaan Yılmaz Mar 17 '18 at 14:41
  • please dont use * for this. This tells spring boot that the request can be made from any origin, and this could lead to security vulnerabilities. – Jp Silver Nov 04 '21 at 05:17
  • @JpSilver this is just for development environment – Y.Kaan Yılmaz Nov 29 '21 at 10:24
0

If you are using a IIS server It was a problem with the WebDAVModule which seems to block PUT and DELETE methods by default!

<system.webServer>
  <modules runAllManagedModulesForAllRequests="false">
    <remove name="WebDAVModule" />
  </modules>
</system.webServer>

I really hope no one else pain with that! =]

Fonte: https://mozartec.com/asp-net-core-error-405-methods-not-allowed-for-put-and-delete-requests-when-hosted-on-iis/

0

In Spring with Kotlin I did the following:

@Bean
fun corsConfigurationSource(): CorsConfigurationSource? {
    val source = UrlBasedCorsConfigurationSource()

    val corsConfig = CorsConfiguration()
        .applyPermitDefaultValues()
        .setAllowedOriginPatterns(listOf("*"))
    corsConfig.addAllowedMethod(HttpMethod.PUT)
    source.registerCorsConfiguration("/**", corsConfig)

    return source
}
0

I just want to add 3 things.

  1. The accepted answer and the one below it are wrong ways of doing CORS. If you are trying to configure CORS, that means you are trying to make your API accessible only by a number of clients you know. The lines

    configuration.setAllowedOrigins(ImmutableList.of("*")); // from the first answer
    
    .addMapping("/**") // from the second answer
    

    make the API accessible by any client. If that is what you want, you can just do the following with out a need to configure another bean

    http.cors().disable()
    
  2. The issue in the question may happen when you allow origins with http and do your request using https. So be aware that those 2 are different.

  3. Below is a working configuration

    // In the import section
    import static org.springframework.security.config.Customizer.withDefaults;
    
    // In the HttpSecurity configuration
    http.cors(withDefaults())
    
     @Bean
     public CorsConfigurationSource corsConfigurationSource() {
       final CorsConfiguration configuration = new CorsConfiguration();
       configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200", "https://localhost:4200"));
       configuration.setAllowedMethods(Arrays.asList("HEAD",
             "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
       configuration.setAllowCredentials(true);
       configuration.setAllowedHeaders(Arrays.asList("Content-Type", "X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
       configuration.setExposedHeaders(Arrays.asList("Content-Type", "X-Auth-Token","Authorization","Access-Control-Allow-Origin","Access-Control-Allow-Credentials"));
       final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
       source.registerCorsConfiguration("/**", configuration);
       return source;
     }
    
Dejazmach
  • 742
  • 8
  • 15
0

I'm using Spring Security and Spring Boot 2.1.2. In my specific case, the PUT call worked after I explicitly declared the "PUT" method in the setAllowedMethods() from CorsConfigurationSource bean. The headers can be chosen depending on the application behavior.

@Bean
CorsConfigurationSource corsConfigurationSource() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final String headers =  "Authorization, Access-Control-Allow-Headers, "+
                            "Origin, Accept, X-Requested-With, Content-Type, " + 
                            "Access-Control-Request-Method, Custom-Filter-Header";
    
    CorsConfiguration config = new CorsConfiguration();

    config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE")); // Required for PUT method
    config.addExposedHeader(headers);
    config.setAllowCredentials(true);
    config.applyPermitDefaultValues();
    
    source.registerCorsConfiguration("/**", config);
    
    return source;
}
lrpuppi
  • 1
  • 2