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-конфігурація
Щоб активувати 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.
Щоб конфігурувати фільтр, передай 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)