Thursday, June 9, 2016

Spring boot - is it possible to have Global Cors Configuration using only application.properties?

No, not for Spring Boot 1.3.1.RELEASE at least.

I have a Spring Boot backend application, and an AngularJS front-end application; they run on application servers on different ports (front end on port 3000, backend on port 8443). Because of this, the spring boot application needed to support CORS.

OLD
I originally had the application set up with Global CORS configuration, similar to the following.  All REST endpoints, HTTP GET/PUT/POST supported, with localhost port 3000 as the allowed Origin.

public class CherryShoeApplication {
    public static void main(String[] args) {
        SpringApplication.run(CherryShoeApplication.class, args);
    }
    
    /*
     * Since spring boot 1.3, Global CORS configuration can be defined by registering 
     * a WebMvcConfigurer bean with a customized addCorsMappings(CorsRegistry) method
     */
     @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                .allowedMethods("GET", "PUT", "POST")
                .allowedOrigins("http://localhost:3000")
                ;
             }
         };
    }
}

Needed to update the WebSecurityConfig to allow all HTTP OPTIONS through.  Spring Security pre-authorization was used to protect the application, in this particular example.

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(ssoFilter(),
        RequestHeaderAuthenticationFilter.class)
        .authenticationProvider(preauthAuthProvider()).csrf().disable()
        .authorizeRequests()
        .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // allow CORS OPTIONS calls through
        .anyRequest().authenticated();
    }
}

NEW
I wanted to move Global CORS configuration out of the Java Config and into application.properties, so it'd be easier to update without a code update.

The same Java Config above (public WebMvcConfigurer corsConfigurer()) is now configured as the following in application.properties:

# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
# Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allow-credentials=false
# Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-headers=*
# Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-methods=GET,PUT,POST
# Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.allowed-origins=http://localhost:3000
# Comma-separated list of extra headers to include in a response, these get exposed by default 
# Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
#endpoints.cors.exposed-headers=
# How long, in seconds, the response from a pre-flight request can be cached by clients. 
#endpoints.cors.max-age=1800 

Key takeaway:
There was no way to do a global cors configuration via essentially an "empty" WebMvcConfigurer corsConfigurer (In other words, completely removing the WebMvcConfigurer corsConfigurer @Bean/method), and then use only the application.properties to configure it.  To get the application.properties cors parameters recognized, the @CrossOrigin annotation also needs to be added to each controller. I decided to create a base class and have each controller extend it, so it'd be easier to maintain in the future.

/**
 * Base class so all controllers can extend this class to inherit the @CrossOrigin annotation
 */
@CrossOrigin
public class CrossOriginController {
    // empty, just need the CrossOrigin annotation
}

If you know of any other way to do a global cors configuration using application.propeties cors parameters, please let me know!

3 comments:

  1. You did point out one item that I found interesting: I hadn't found anything that said that the @CrossOrigin notation was required for the application.properties to take effect. I did notice that I could just add the notation, with nothing in the properties file and everything worked. And, if I didn't use the notation, and only used the properties file, the user did receive CORS errors.

    ReplyDelete
  2. refer here: http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html

    springboot support 2 properties for CORS support:

    endpoints.cors.allowed-origins=http://example.com
    endpoints.cors.allowed-methods=GET,POST

    ReplyDelete
    Replies
    1. Key point for this article was:

      There was no way to do a global cors configuration via essentially an "empty" WebMvcConfigurer corsConfigurer, and then use the application.properties to configure it. To get the application.properties cors parameters recognized, the @CrossOrigin annotation needs to be added to each controller. I decided to create a base class and have each controller extend it, so it'd be easier to maintain in the fugure.

      Delete

I appreciate your time in leaving a comment!