For security reasons, browsers prohibit AJAX calls to resources residing outside the current origin. For example, as you’re checking your bank account in one tab, you could have the evil.com website open in another tab. The scripts from evil.com should not be able to make AJAX requests to your bank API (e.g., withdrawing money from your account!) using your credentials.
Cross-origin resource sharing (CORS) is a W3C specification implemented by most browsers that allows you to specify in a flexible way what kind of cross domain requests are authorized, instead of using some less secured and less powerful hacks like IFRAME or JSONP.
As of Spring Framework 4.2, CORS is supported out of the box. CORS requests
(including preflight ones with an OPTIONS
method)
are automatically dispatched to the various registered HandlerMapping
s. They handle
CORS preflight requests and intercept CORS simple and actual requests thanks to a
CorsProcessor
implementation (DefaultCorsProcessor
by default) in order to add the relevant CORS response headers (like Access-Control-Allow-Origin
)
based on the CORS configuration you have provided.
Note | |
---|---|
Since CORS requests are automatically dispatched, you do not need to change the
|
You can add an
@CrossOrigin
annotation to your @RequestMapping
annotated handler method in order to enable CORS on
it. By default @CrossOrigin
allows all origins and the HTTP methods specified in the
@RequestMapping
annotation:
@RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }
It is also possible to enable CORS for the whole controller:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }
In the above example CORS support is enabled for both the retrieve()
and the remove()
handler methods, and you can also see how you can customize the CORS configuration using
@CrossOrigin
attributes.
You can even use both controller-level and method-level CORS configurations; Spring will then combine attributes from both annotations to create merged CORS configuration.
@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("https://domain2.com") @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }
In addition to fine-grained, annotation-based configuration you’ll probably want to
define some global CORS configuration as well. This is similar to using filters but can
be declared within Spring MVC and combined with fine-grained @CrossOrigin
configuration.
By default all origins and GET
, HEAD
, and POST
methods are allowed.
Enabling CORS for the whole application is as simple as:
@Configuration @EnableWebMvc public class WebConfig extends 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:
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(false).maxAge(3600); } }
The following minimal XML configuration enables CORS for the /**
path pattern with
the same default properties as with the aforementioned JavaConfig examples:
<mvc:cors> <mvc:mapping path="/**" /> </mvc:cors>
It is also possible to declare several CORS mappings with customized properties:
<mvc:cors> <mvc:mapping path="/api/**" allowed-origins="https://domain1.com, https://domain2.com" allowed-methods="GET, PUT" allowed-headers="header1, header2, header3" exposed-headers="header1, header2" allow-credentials="false" max-age="123" /> <mvc:mapping path="/resources/**" allowed-origins="https://domain1.com" /> </mvc:cors>
CorsConfiguration allows you to specify how the CORS requests should be processed: allowed origins, headers, methods, etc. It can be provided in various ways:
AbstractHandlerMapping#setCorsConfiguration()
allows to specify a Map
with several CorsConfiguration
instances mapped to path patterns like /api/**
.
CorsConfiguration
by overriding the
AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest)
method.
CorsConfigurationSource
interface (like ResourceHttpRequestHandler
now does) in order to provide a CorsConfiguration
instance for each request.
In order to support CORS with filter-based security frameworks like
Spring Security, or
with other libraries that do not support natively CORS, Spring Framework also
provides a CorsFilter
.
Instead of using @CrossOrigin
or WebMvcConfigurer#addCorsMappings(CorsRegistry)
, you
need to register a custom filter defined like bellow:
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; public class MyCorsFilter extends CorsFilter { public MyCorsFilter() { super(configurationSource()); } private static UrlBasedCorsConfigurationSource configurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("https://domain1.com"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }
You need to ensure that CorsFilter
is ordered before the other filters, see
this blog post
about how to configure Spring Boot accordingly.