Spring MVC позволяет обрабатывать CORS (совместное использование ресурсов между разными источниками).
Введение
Из соображений безопасности браузеры запрещают AJAX-обращения к ресурсам за пределами текущего источника. Например, у вас может быть свой банковский счет на одной вкладке, а evil.com – на другой. Скрипты с сайта evil.com не должны иметь возможности осуществлять AJAX-запросы к API вашего банка с вашими учетными данными – например, снимать деньги с вашего счета!
Совместное использование ресурсов между разными источниками (CORS) – это спецификация W3C, реализованная в большинстве браузеров, которая позволяет определять, какие междоменные запросы разрешены, вместо того, чтобы использовать менее безопасные и менее мощные обходные пути, основанные на IFRAME или JSONP.
Обработка
Спецификация CORS различает предварительные, простые и фактические запросы. Чтобы понять, как работает CORS, можете ознакомиться с этой статьей, помимо прочего, или обратиться за подробной информацией к спецификации.
Реализации HandlerMapping
из Spring MVC обеспечивают встроенную поддержку CORS. После успешного отображения запроса на обработчик, реализации HandlerMapping
проверяют конфигурацию CORS для данного запроса и обработчика и предпринимают дальнейшие действия. Предварительные запросы обрабатываются напрямую, а простые и фактические CORS-запросы перехватываются, валидируются, и для них устанавливаются необходимые заголовки CORS-ответа.
Для того чтобы разрешить запросы между разными источниками (то есть заголовок Origin
присутствует и отличается от хоста запроса), вам необходимо обеспечить некоторую явно объявленную конфигурацию CORS. Если подходящей конфигурации CORS не найдена, то предварительные запросы отклоняются. В ответы на простые и фактические CORS-запросы не добавляются CORS-заголовки, и, следовательно, браузеры их отклоняют.
Каждый HandlerMapping
может быть сконфигурирован индивидуально с помощью отображений CorsConfiguration
на основе URL-шаблонов. В большинстве случаев приложения используют Java-конфигурацию MVC или пространство имен XML для объявления таких отображений, в результате чего всем экземплярам HandlerMapping
передается одна глобальная Map.
Можно сочетать глобальную настройку CORS на уровне HandlerMapping
с более тонкой настройкой CORS на уровне обработчиков. Например, аннотированные контроллеры могут использовать аннотации @CrossOrigin
на уровне классов или методов (другие обработчики могут реализовать CorsConfigurationSource
).
Правила комбинирования глобальной и локальной конфигурации обычно аддитивны – например, все глобальный и все локальные источники. Для тех атрибутов, где может быть принято только одно значение, например, allowCredentials
и maxAge
, локальное значение переопределяет глобальное. Более подробную информацию см. в разделе, посвященном CorsConfiguration#combine(CorsConfiguration)
.
Чтобы почерпнуть больше из источника или осуществить расширенную настройку, ознакомьтесь с кодом:
-
CorsConfiguration
-
CorsProcessor
,DefaultCorsProcessor
-
AbstractHandlerMapping
@CrossOrigin
Аннотация @CrossOrigin
позволяет выполнять запросы между разными источниками к аннотированным методам контроллера, как показано в следующем примере:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
}
По умолчанию @CrossOrigin
разрешает:
-
Все источники.
-
Все заголовки.
-
Все HTTP-методы, с которыми сопоставлен метод контроллера.
allowCredentials
не активирован по умолчанию, так как это устанавливает уровень доверия, при котором раскрывается конфиденциальная информация о пользователе (такая как cookies и CSRF-токены), поэтому его нужно использовать только в тех случаях, где это действительно необходимо. Если он активирован, то либо allowOrigins
должен быть установлен для одного или нескольких определенных доменов (но не специальное значение "*"
), либо, как вариант, можно использовать свойство allowOriginPatterns для сопоставления с динамическим набором источников.
maxAge
устанавливается на 30 минут.
Аннотация @CrossOrigin
поддерживается на уровне класса и также наследуется всеми методами, как показано в следующем примере:
@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) {
// ...
}
}
@CrossOrigin(origins = ["https://domain2.com"], maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
Вы можете использовать аннотацию @CrossOrigin
как на уровне класса, так и на уровне метода, как показано в следующем примере:
@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) {
// ...
}
}
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
}
Глобальная конфигурация
В дополнение к тонкой настройке на уровне методов контроллера, вам, вероятно, понадобится определить и глобальную конфигурацию CORS. Вы можете настроить отображения CorsConfiguration
на основе URL-адресов индивидуально для любого HandlerMapping
. Однако большинство приложений используют для этого конфигурацию MVC в Java или пространство имен MVC в XML.
По умолчанию глобальная конфигурация активирует следующее:
-
Все источники.
-
Все заголовки.
-
Методы
GET
,HEAD
иPOST
.
allowCredentials
не активирован по умолчанию, так как это устанавливает уровень доверия, при котором раскрывается конфиденциальная информация о пользователе (такая как cookies и CSRF-токены), поэтому его нужно использовать только в тех случаях, где это действительно необходимо. Если он активирован, то либо allowOrigins
должен быть установлен для одного или нескольких определенных доменов (но не специальное значение "*"
), либо, как вариант, можно использовать свойство allowOriginPatterns для сопоставления с динамическим набором источников.
maxAge
устанавливается на 30 минут.
Java-конфигурацияn
Чтобы активировать CORS в Java-конфигурации MVC, можно использовать обратный вызов CorsRegistry
, как показано в следующем примере:
@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);
// Добавляем больше отображений...
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600)
// Добавляем больше отображений...
}
}
XML-конфигурация
Чтобы активировать CORS в пространстве имен XML, можно использовать элемент <mvc:cors>
, как показано в следующем примере:
<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>
CORS-фильтр
Вы можете применить поддержку CORS через встроенный CorsFilter
.
CorsFilter
со Spring Security, имейте в виду, что Spring Security предусматривает <встроенную поддержку CORS. < div>
Чтобы сконфигурировать фильтр, передайте CorsConfigurationSource
в его конструктор, как показано в следующем примере:
CorsConfiguration config = new CorsConfiguration();
// Возможно...
// 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);
val config = CorsConfiguration()
// Возможно...
// config.applyPermitDefaultValues()
config.allowCredentials = true
config.addAllowedOrigin("https://domain1.com")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", config)
val filter = CorsFilter(source)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ