Spring MVC дозволяє обробляти CORS (спільне використання ресурсів між різними джерелами).
З міркувань безпеки браузери забороняють AJAX-звернення до ресурсів за межами поточного походження. Наприклад, у тебе може бути свій банківський рахунок на одній вкладці, а evil.com — на іншій. Скрипти із сайту evil.com не повинні мати можливості здійснювати AJAX-запити до API вашого банку з твоїми обліковими даними — наприклад, знімати гроші з твого рахунку!
Спільне використання ресурсів між різними джерелами (CORS) — це специфікація W3C, реалізована в більшості браузерів, яка дозволяє визначати, які міждоменні запити дозволені, замість того, щоб використовувати менш безпечні та менш потужні обхідні шляхи, засновані на IFRAME або JSONP.
Обробка
Специфікація CORS розрізняє попередні, прості та фактичні запити. Щоб зрозуміти, як працює CORS, можна звернутися за детальною інформацією до специфікації.
Реалізації
HandlerMapping
із Spring WebFlux
забезпечують вбудовану підтримку CORS. Після успішного відображення запиту на обробник, HandlerMapping
перевіряє конфігурацію CORS для даного запиту та обробника і робить подальші дії. Попередні запити обробляються
безпосередньо, а прості та фактичні CORS-запити перехоплюються, валідуються, і для них встановлюються необхідні
заголовки CORS-відповіді.
Щоб дозволити запити між різними джерелами (тобто заголовок Origin
є і
відрізняється від хоста запиту), тобі необхідно забезпечити деяку явно оголошену конфігурацію CORS. Якщо
відповідної конфігурації CORS не знайдено, попередні запити відхиляються. У відповіді на прості та фактичні
CORS-запити не додаються CORS-заголовки, і, отже, браузери їх відхиляють.
Кожен HandlerMapping
може бути конфігурований індивідуально за допомогою відображень CorsConfiguration
на
основі URL-шаблонів. У більшості випадків програми використовують Java-конфігурацію WebFlux для оголошення таких
відображень, що призводить до створення єдиної глобальної Map, що передається всім реалізаціям
HandlerMapping
.
Можна поєднувати глобальну конфігурацію 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 Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin
@GetMapping("/{id}")
suspend fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
suspend fun remove(@PathVariable id: Long) {
// ...
}
}
За замовчуванням @CrossOrigin
дозволяє:
Всі джерела.
Всі заголовки.
Всі HTTP-методи, з якими зіставлений метод контролера.
allowCredentials
не активовано за замовчуванням, оскільки це встановлює рівень довіри, при якому
розкривається конфіденційна інформація про користувача (така як файли cookie та (CSRF-токени), тому його слід
використовувати тільки в тих випадках, коли це дійсно необхідно. Якщо він активований, то або
allowOrigins
має бути встановлений для одного або декількох певних доменів (але не спеціальне значення
"*"
), або, як варіант, можна використовувати властивість allowOriginPatterns для зіставлення з
динамічним набором джерел.
maxAge
is set to 30 minutes.
@CrossOrigin
підтримується на рівні класу і успадковується всіма способами. У наступному прикладі вказано певний домен і задано
значення maxAge
дорівнює годині:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
@CrossOrigin("https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@GetMapping("/{id}")
suspend fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
suspend fun remove(@PathVariable id: Long) {
// ...
}
}
Ти можеш використовувати анотацію @CrossOrigin
як на рівні класу, так і на рівні методу, як це
показано в наступному прикладі:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
public Mono<Account> retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public Mono<Void> remove(@PathVariable Long id) {
// ...
}
}
- Використання анотації
@CrossOrigin
на рівні класу. - Використання анотації
@CrossOrigin
на рівні методу.
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
suspend fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
suspend fun remove(@PathVariable id: Long) {
// ...
}
}
- Використання анотації
@CrossOrigin
на рівні класу. - Використання анотації
@CrossOrigin
на рівні методу.
Глобальна конфігурація
На додаток до тонкого настроювання на рівні методів контролера, тобі,
ймовірно, знадобиться визначити і глобальну конфігурацію CORS. Ти можеш налаштувати відображення CorsConfiguration
на основі URL-адрес індивідуально для будь-якого HandlerMapping
. Проте більшість програм використовують
для цього Java-конфігурацію WebFlux.
За замовчуванням глобальна конфігурація включає таке:
Всі джерела.
Всі заголовки.
Методи
GET
,HEAD
таPOST
.
allowCredentials
не активовано за замовчуванням, оскільки це встановлює рівень довіри, при якому
розкривається конфіденційна інформація про користувача (така як файли cookie та CSRF-токени), тому його слід
використовувати тільки в тих випадках, коли це дійсно необхідно. Якщо він активований, то або
allowOrigins
повинен бути встановлений для одного яи кількох певних доменів (але не спеціальне
значення "* "
), або, як варіант, можна використовувати властивість allowOriginPatterns для зіставлення
з динамічним набором джерел.
maxAge
is set to 30 minutes.
Щоб активувати CORS у
Java-конфігурації WebFlux, можна використовувати зворотний виклик CorsRegistry
, як показано в
наступному прикладі:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@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
@EnableWebFlux
class WebConfig : WebFluxConfigurer {
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)
// Додаємо ще відображень...
}
}
WebFilter
для CORS
Ти можеш застосувати засоби підтримки CORS через вбудований CorsWebFilter
, який відмінно підходить для функціональних кінцевих точок.
CorsFilter
зі Spring
Security, май на увазі, що Spring Security передбачає вбудовану
підтримку CORS.
Для налаштування фільтра можна оголосити бін CorsWebFilter
і передати
CorsConfigurationSource
до його конструктора, як показано в наступному прикладі:
@Bean
CorsWebFilter corsFilter() {
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);
return new CorsWebFilter(source);
}
@Bean
fun corsFilter(): CorsWebFilter {
val config = CorsConfiguration()
// Можливо...
// config.applyPermitDefaultValues()
config.allowCredentials = true
config.addAllowedOrigin("https://domain1.com")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
val source = UrlBasedCorsConfigurationSource().apply {
registerCorsConfiguration("/**", config)
}
return CorsWebFilter(source)
}
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ