1. Обзор
В любом современном браузере совместное использование ресурсов между источниками (CORS) является актуальной спецификацией с появлением клиентов HTML5 и JS, которые потребляют данные через REST API.
Часто хост, который обслуживает JS (например, example.com), отличается от хоста, который обслуживает данные (например, api.example.com). В таком случае CORS обеспечивает междоменное взаимодействие.
Spring обеспечивает первоклассную поддержку CORS, предлагая простой и эффективный способ его настройки в любом веб-приложении Spring или Spring Boot.
2. Конфигурация CORS метода контроллера
Включить CORS очень просто — просто добавьте аннотацию @CrossOrigin
.
Мы можем реализовать это несколькими различными способами.
2.1. @CrossOrigin
в методе аннотированного обработчика @RequestMapping-
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@RequestMapping(method = RequestMethod.GET, path = "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
В приведенном выше примере мы включили CORS только для метода retrieve() .
Мы видим, что мы не задавали никаких настроек для аннотации @CrossOrigin
, поэтому используются значения по умолчанию:
- Все происхождения разрешены.
- Разрешены методы HTTP, указанные в аннотации
@RequestMapping
(GET, в данном примере). - Время кэширования ответа предварительной проверки (
maxAge
) составляет 30 минут.
2.2. @CrossOrigin
на контроллере
@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@RequestMapping(method = RequestMethod.GET, path = "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
На этот раз мы добавили @CrossOrigin
на уровне класса. Таким образом, оба метода retrieve()
и remove()
включены. Мы можем настроить конфигурацию, указав значение одного из атрибутов аннотации: origins
, methods
, allowHeaders
, posedHeaders
, allowCredentials
или maxAge
.
2.3. @CrossOrigin
в контроллере и методе обработчика
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("http://example.com")
@RequestMapping(method = RequestMethod.GET, "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
Spring объединит атрибуты из обеих аннотаций для создания объединенной конфигурации CORS.
Здесь оба метода будут иметь maxAge
3600 секунд, метод remove()
разрешит все источники, а метод retrieve()
разрешит только источники с http://example.com
.
3. Глобальная конфигурация CORS
В качестве альтернативы мелкозернистой конфигурации на основе аннотаций Spring позволяет нам определить некоторую глобальную конфигурацию CORS из наших контроллеров. Это похоже на использование решения на основе фильтра
, но может быть объявлено в Spring MVC и объединено с мелкозернистой конфигурацией @CrossOrigin
.
По умолчанию разрешены все источники и методы GET, HEAD и POST.
3.1. JavaConfig
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
В приведенном выше примере разрешаются запросы CORS из любого источника в любую конечную точку в приложении.
Чтобы еще больше зафиксировать это, метод register.addMapping возвращает объект CorsRegistration
,
который мы можем использовать для дополнительной настройки. Также есть метод allowOrigins
, который позволяет указать массив разрешенных источников. Это может быть полезно, если нам нужно загрузить этот массив из внешнего источника во время выполнения.
Кроме того, есть также AllowMethods
, AllowHeaders
, visibleHeaders
, maxAge
и allowCredentials
, которые мы можем использовать для установки заголовков ответа и параметров настройки.
3.2. Пространство имен XML
Эта минимальная конфигурация XML включает CORS в шаблоне пути /**
с теми же свойствами по умолчанию, что и в JavaConfig:
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
Также можно объявить несколько сопоставлений CORS с настраиваемыми свойствами:
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="false"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
4. CORS с Spring Security
Если мы используем Spring Security в нашем проекте, мы должны сделать дополнительный шаг, чтобы убедиться, что он хорошо работает с CORS. Это связано с тем, что сначала необходимо обработать CORS. В противном случае Spring Security отклонит запрос до того, как он достигнет Spring MVC.
К счастью, Spring Security предоставляет готовое решение:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
В этой статье это объясняется более подробно.
5. Как это работает
Запросы CORS автоматически отправляются в различные зарегистрированные HandlerMappings
. Они обрабатывают предварительные запросы CORS и перехватывают простые и фактические запросы CORS с помощью реализации CorsProcessor
( по умолчанию DefaultCorsProcessor
) для добавления соответствующих заголовков ответов CORS (таких как Access-Control-Allow-Origin
).
CorsConfiguration
позволяет нам указать, как должны обрабатываться запросы CORS, включая разрешенные источники, заголовки и методы, среди прочего. Мы можем предоставить его различными способами:
AbstractHandlerMapping#setCorsConfiguration()
позволяет нам указатьMap
с несколькимиCorsConfiguration ,
сопоставленными с шаблонами пути, такими как/api/**
.- Подклассы могут предоставлять свои собственные
CorsConfiguration
, переопределяя методAbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest)
. - Обработчики могут реализовать интерфейс
CorsConfigurationSource
(как сейчас делаетResourceHttpRequestHandler
), чтобы предоставитьCorsConfiguration
для каждого запроса.
6. Заключение
В этой статье мы показали, как Spring обеспечивает поддержку включения CORS в нашем приложении.
Начали с настройки контроллера. Мы увидели, что нам нужно только добавить аннотацию @CrossOrigin
, чтобы включить CORS либо для одного конкретного метода, либо для всего контроллера.
Кроме того, мы узнали, что для управления конфигурацией CORS вне контроллеров мы можем легко выполнять это в файлах конфигурации, используя либо JavaConfig, либо XML.
Полный исходный код примеров доступен на GitHub .