DEV Community

Cover image for Automatically add CORS configuration to Spring controllers
Ulrich VACHON
Ulrich VACHON

Posted on • Updated on

Automatically add CORS configuration to Spring controllers

It could be useful to add with a less of code the expected CORS headers in your Spring boot configuration. Let's do this!

CORS (Cross-Origin Resource Sharing) is a mechanism that allows "to protect" your resources APIs from undesirated calls. By saying protect I mean restrict the resources to be requested by any domain outside the origin domain where the resources was served.

Flag all resources with @CrossOrigin

This is the only step required by the configurer to claim the cross origin resource sharing. For example :

@CrossOrigin
@RestController
@RequestMapping(value = "/api/user")
public interface UserController { ...
Enter fullscreen mode Exit fullscreen mode

Declare the CORS Spring configurer

This Spring bean is responsible of several things 🔎 The first one action is to scan your resources looking for the paths will should be protected. In this example we use the autowired bean ApplicationContext as entry point in the Spring application context :

@Autowired
public CorsConfig(ApplicationContext applicationContext) {
    corsControllers = Stream.of(applicationContext.getBeanNamesForAnnotation(CrossOrigin.class))
            .filter(Objects::nonNull)
            .map(bean -> applicationContext.findAnnotationOnBean(bean, RequestMapping.class))
            .filter(mapping -> Objects.nonNull(mapping) && mapping.path().length > 0)
            .map(mapping -> mapping.path()[0])
            .peek(path -> log.info("Register CORS configuration for \"{}\".", path))
            .collect(toSet());
}
Enter fullscreen mode Exit fullscreen mode

Please keep this code safe !

The second one action is to declare WebMvcConfigurer bean will add the protected path in the CORS Registry.

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            for (String corsController : corsControllers) {
                registry.addMapping(corsController)
                        .allowedOriginPatterns(allowedCorsOrigin)
                        .allowedHeaders("Authorization", ...)
                        .allowedMethods("OPTIONS", "PUT", "POST", ...);
            }
        }
    };
}
Enter fullscreen mode Exit fullscreen mode

Something interresting to note there is that we can externalize the declaration of allowed domains by Ant patterns in an array of String. The property allowedCorsOrigin is a variable annoted by @Value (see the sample code).

Test the Spring configuration with CURL

Now we are able to test the configuration in a real Spring app.

🟢Here we use a valid domain for test :

❯ curl -H "Origin: https://fr.reservoircode.net" --verbose http://localhost:9999/api/user
*   Trying 127.0.0.1:9999...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9999 (#0)
> GET /api/user HTTP/1.1
> Host: localhost:9999
> User-Agent: curl/7.68.0
> Accept: */*
> Origin: https://fr.reservoircode.net
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Access-Control-Allow-Origin: https://fr.reservoircode.net
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 20 May 2022 16:20:17 GMT
< 
* Connection #0 to host localhost left intact
{"id":"1","name":"Ulrich"}
Enter fullscreen mode Exit fullscreen mode

🔴Here we use a invalid domain for test :

❯ curl -H "Origin: https://foo.com" --verbose http://localhost:9999/api/user       
*   Trying 127.0.0.1:9999...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9999 (#0)
> GET /api/user HTTP/1.1
> Host: localhost:9999
> User-Agent: curl/7.68.0
> Accept: */*
> Origin: https://foo.com
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Transfer-Encoding: chunked
< Date: Fri, 20 May 2022 16:23:02 GMT
< 
* Connection #0 to host localhost left intact
Invalid CORS request
Enter fullscreen mode Exit fullscreen mode

Let me try it

If you want a Spring boot example you can clone the repository https://github.com/ulrich/spring-cors-autoconfig

Crédit photo : https://pixabay.com/fr/users/jackmac34-483877/

Top comments (0)