Spring MVC lets you handle CORS (Cross-Origin Resource Sharing). This section describes how to do so.
For security reasons, browsers prohibit AJAX calls to resources outside the current origin. For example, you could have your bank account in one tab and evil.com in another. Scripts from evil.com should not be able to make AJAX requests to your bank API with your credentials — for example withdrawing money from your account!
Cross-Origin Resource Sharing (CORS) is a W3C specification implemented by most browsers that lets you specify what kind of cross-domain requests are authorized, rather than using less secure and less powerful workarounds based on IFRAME or JSONP.
The CORS specification distinguishes between preflight, simple, and actual requests. To learn how CORS works, you can read this article, among many others, or see the specification for more details.
Spring MVC HandlerMapping
implementations provide built-in support for CORS. After successfully
mapping a request to a handler, HandlerMapping
implementations check the CORS configuration for the
given request and handler and take further actions. Preflight requests are handled
directly, while simple and actual CORS requests are intercepted, validated, and have
required CORS response headers set.
In order to enable cross-origin requests (that is, the Origin
header is present and
differs from the host of the request), you need to have some explicitly declared CORS
configuration. If no matching CORS configuration is found, preflight requests are
rejected. No CORS headers are added to the responses of simple and actual CORS requests
and, consequently, browsers reject them.
Each HandlerMapping
can be
{api-spring-framework}/web/servlet/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-[configured]
individually with URL pattern-based CorsConfiguration
mappings. In most cases, applications
use the MVC Java configuration or the XML namespace to declare such mappings, which results
in a single global map being passed to all HandlerMappping
instances.
You can combine global CORS configuration at the HandlerMapping
level with more
fine-grained, handler-level CORS configuration. For example, annotated controllers can use
class- or method-level @CrossOrigin
annotations (other handlers can implement
CorsConfigurationSource
).
The rules for combining global and local configuration are generally additive — for example,
all global and all local origins. For those attributes where only a single value can be
accepted (such as allowCredentials
and maxAge
), the local overrides the global value. See
{api-spring-framework}/web/cors/CorsConfiguration.html#combine-org.springframework.web.cors.CorsConfiguration-[CorsConfiguration#combine(CorsConfiguration)
]
for more details.
Tip
|
To learn more from the source or make advanced customizations, check the code behind:
|
The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[@CrossOrigin
]
annotation enables cross-origin requests on annotated controller methods,
as the following example shows:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
By default, @CrossOrigin
allows:
-
All origins.
-
All headers.
-
All HTTP methods to which the controller method is mapped.
allowedCredentials
is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should only be used where appropriate.
maxAge
is set to 30 minutes.
@CrossOrigin
is supported at the class level, too, and is inherited by all methods,
as the following example shows:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
You can use @CrossOrigin
at both the class level and the method level,
as the following example shows:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
In addition to fine-grained, controller method level configuration, you probably want to
define some global CORS configuration, too. You can set URL-based CorsConfiguration
mappings individually on any HandlerMapping
. Most applications, however, use the
MVC Java configuration or the MVC XNM namespace to do that.
By default, global configuration enables the following:
-
All origins.
-
All headers.
-
GET
,HEAD
, andPOST
methods.
allowedCredentials
is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should only be used where appropriate.
maxAge
is set to 30 minutes.
To enable CORS in the MVC Java config, you can use the CorsRegistry
callback,
as the following example shows:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
// Add more mappings...
}
}
To enable CORS in the XML namespace, you can use the <mvc:cors>
element,
as the following example shows:
<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="true"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="https://domain1.com" />
</mvc:cors>
You can apply CORS support through the built-in
{api-spring-framework}/web/filter/CorsFilter.html[CorsFilter
].
Note
|
If you try to use the CorsFilter with Spring Security, keep in mind that
Spring Security has
built-in support
for CORS.
|
To configure the filter, pass a
CorsConfigurationSource
to its constructor, as the following example shows:
CorsConfiguration config = new CorsConfiguration();
// Possibly...
// config.applyPermitDefaultValues()
config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);