2017-08-23 22:00:26 +08:00
[[mvc-cors]]
2017-10-07 01:11:15 +08:00
= CORS
2015-06-29 21:15:16 +08:00
2017-10-19 02:24:17 +08:00
2015-06-29 21:15:16 +08:00
== Introduction
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
2015-06-29 22:40:50 +08:00
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!)
2015-06-29 21:15:16 +08:00
using your credentials.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing[Cross-origin resource sharing]
(CORS) is a http://www.w3.org/TR/cors/[W3C specification] implemented by
http://caniuse.com/#feat=cors[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
2015-06-29 22:40:50 +08:00
and less powerful hacks like IFRAME or JSONP.
2015-06-29 21:15:16 +08:00
As of Spring Framework 4.2, CORS is supported out of the box. CORS requests
(https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java#L906[including preflight ones with an `OPTIONS` method])
2016-06-11 18:51:38 +08:00
are automatically dispatched to the various registered ``HandlerMapping``s. They handle
2015-06-29 21:15:16 +08:00
CORS preflight requests and intercept CORS simple and actual requests thanks to a
2015-10-27 21:31:00 +08:00
{api-spring-framework}/web/cors/CorsProcessor.html[CorsProcessor]
2015-06-29 21:15:16 +08:00
implementation (https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/cors/DefaultCorsProcessor.java[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.
2017-11-22 18:38:55 +08:00
[NOTE]
====
Be aware that cookies are not allowed by default to avoid increasing the surface attack of
the web application (for example via exposing sensitive user-specific information like
CSRF tokens). Set `allowedCredentials` property to `true` in order to allow them.
====
2015-06-29 21:15:16 +08:00
[NOTE]
====
2015-06-29 22:40:50 +08:00
Since CORS requests are automatically dispatched, you *do not need* to change the
`DispatcherServlet` `dispatchOptionsRequest` init parameter value; using its default value
2015-06-29 21:15:16 +08:00
(`false`) is the recommended approach.
====
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-controller]]
2017-11-15 23:16:13 +08:00
== @CrossOrigin
2015-06-29 21:15:16 +08:00
2015-06-29 22:40:50 +08:00
You can add an
2015-10-27 21:31:00 +08:00
{api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
2015-06-29 22:40:50 +08:00
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:
2015-06-29 21:15:16 +08:00
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RestController
2016-08-26 19:57:18 +08:00
@RequestMapping("/account")
2015-06-29 21:15:16 +08:00
public class AccountController {
@CrossOrigin
2017-11-15 23:16:13 +08:00
@GetMapping("/{id}")
2015-06-29 21:15:16 +08:00
public Account retrieve(@PathVariable Long id) {
// ...
}
2017-11-15 23:16:13 +08:00
@DeleteMapping("/{id}")
2015-06-29 21:15:16 +08:00
public void remove(@PathVariable Long id) {
// ...
}
}
----
It is also possible to enable CORS for the whole controller:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
2016-08-26 19:57:18 +08:00
@RequestMapping("/account")
2015-06-29 21:15:16 +08:00
public class AccountController {
2017-11-15 23:16:13 +08:00
@GetMapping("/{id}")
2015-06-29 21:15:16 +08:00
public Account retrieve(@PathVariable Long id) {
// ...
}
2017-11-15 23:16:13 +08:00
@DeleteMapping("/{id}")
2015-06-29 21:15:16 +08:00
public void remove(@PathVariable Long id) {
// ...
}
}
----
2015-06-29 22:40:50 +08:00
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.
2015-06-29 21:15:16 +08:00
2015-06-29 22:40:50 +08:00
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.
2015-06-29 21:15:16 +08:00
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@CrossOrigin(maxAge = 3600)
@RestController
2016-08-26 19:57:18 +08:00
@RequestMapping("/account")
2015-06-29 21:15:16 +08:00
public class AccountController {
2016-08-26 19:57:18 +08:00
@CrossOrigin("http://domain2.com")
@RequestMapping("/{id}")
2015-06-29 21:15:16 +08:00
public Account retrieve(@PathVariable Long id) {
// ...
}
2015-06-29 22:40:50 +08:00
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
2015-06-29 21:15:16 +08:00
public void remove(@PathVariable Long id) {
// ...
}
}
----
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-global]]
2017-10-07 01:11:15 +08:00
== Global CORS
2015-06-29 21:15:16 +08:00
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
2015-06-29 22:40:50 +08:00
be declared within Spring MVC and combined with fine-grained `@CrossOrigin` configuration.
By default all origins and `GET`, `HEAD`, and `POST` methods are allowed.
2015-06-29 21:15:16 +08:00
2017-10-11 04:12:12 +08:00
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-global-java]]
=== Java Config
2015-06-29 21:15:16 +08:00
Enabling CORS for the whole application is as simple as:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
@EnableWebMvc
2017-04-21 04:13:08 +08:00
public class WebConfig implements WebMvcConfigurer {
2015-06-29 21:15:16 +08:00
@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:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
@EnableWebMvc
2017-04-21 04:13:08 +08:00
public class WebConfig implements WebMvcConfigurer {
2015-06-29 21:15:16 +08:00
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
2017-11-22 18:38:55 +08:00
.allowCredentials(true).maxAge(3600);
2015-06-29 21:15:16 +08:00
}
}
----
2017-10-11 04:12:12 +08:00
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-global-xml]]
=== XML Config
2015-06-29 21:15:16 +08:00
2015-06-29 22:40:50 +08:00
The following minimal XML configuration enables CORS for the `/**` path pattern with
the same default properties as with the aforementioned JavaConfig examples:
2015-06-29 21:15:16 +08:00
[source,xml,indent=0]
[subs="verbatim"]
----
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
----
It is also possible to declare several CORS mappings with customized properties:
[source,xml,indent=0]
[subs="verbatim"]
----
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
2017-11-22 18:38:55 +08:00
exposed-headers="header1, header2" allow-credentials="true"
2015-06-29 21:15:16 +08:00
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
----
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-customizations]]
2015-06-29 22:40:50 +08:00
== Advanced Customization
2015-06-29 21:15:16 +08:00
2015-10-27 21:31:00 +08:00
{api-spring-framework}/web/cors/CorsConfiguration.html[CorsConfiguration]
2015-06-29 21:15:16 +08:00
allows you to specify how the CORS requests should be processed: allowed origins, headers, methods, etc.
It can be provided in various ways:
2017-11-15 23:16:13 +08:00
* {api-spring-framework}/web/servlet/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-[`AbstractHandlerMapping#setCorsConfigurations()`]
2015-10-27 21:31:00 +08:00
allows to specify a `Map` with several {api-spring-framework}/web/cors/CorsConfiguration.html[CorsConfiguration]
2015-06-29 22:40:50 +08:00
instances mapped to path patterns like `/api/**`.
* Subclasses can provide their own `CorsConfiguration` by overriding the
`AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest)` method.
2015-10-27 21:31:00 +08:00
* Handlers can implement the {api-spring-framework}/web/cors/CorsConfigurationSource.html[`CorsConfigurationSource`]
2015-06-29 21:15:16 +08:00
interface (like https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java[`ResourceHttpRequestHandler`]
2015-10-27 21:31:00 +08:00
now does) in order to provide a {api-spring-framework}/web/cors/CorsConfiguration.html[CorsConfiguration]
2016-06-28 20:43:53 +08:00
instance for each request.
2017-10-11 04:12:12 +08:00
2017-10-19 02:24:17 +08:00
2017-10-11 04:12:12 +08:00
[[mvc-cors-filter]]
2017-10-07 01:11:15 +08:00
== CORS Filter
2016-06-28 20:43:53 +08:00
2017-11-15 23:16:13 +08:00
You can apply CORS support through the built-in
{api-spring-framework}/web/filter/CorsFilter.html[`CorsFilter`].
[NOTE]
====
Spring Security now provides
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors[builtin support for CORS]
so you don't need to use a `CorsFilter`.
====
To configure the filter pass a
2017-10-11 04:12:12 +08:00
`CorsConfigurationSource` to its constructor:
2016-06-28 20:43:53 +08:00
[source,java,indent=0]
----
2017-10-11 04:12:12 +08:00
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
2016-06-28 20:43:53 +08:00
2017-10-11 04:12:12 +08:00
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
2016-06-28 20:43:53 +08:00
2017-10-11 04:12:12 +08:00
CorsFilter filter = new CorsFilter(source);
2016-06-28 20:43:53 +08:00
----
2017-11-15 23:16:13 +08:00
You can also easily permit all cross-origin requests for GET, HEAD, and POST requests by writing
[source,java,indent=0]
----
CorsFilter filter = new CorsFilter(exchange -> new CorsConfiguration().applyPermitDefaultValues());
----
2017-10-11 04:12:12 +08:00
Also the information on
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors[CORS]
2017-10-19 02:24:17 +08:00
in the Spring Security reference.