Включить CORS весной 5 Webflux?

Как включить CORS в проекте Spring 5 Webflux?

Я не могу найти правильную документацию.

Ответ 1

Вот еще одно решение с конфигуратором Webflux.

Side Note: Код Kotlin (скопирован из моего проекта), но вы можете легко перевести это на Java-код.

@Configuration
@EnableWebFlux
class WebConfig: WebFluxConfigurer
{
    override fun addCorsMappings(registry: CorsRegistry)
    {
        registry.addMapping("/**")
            .allowedOrigins("*") // any host or put domain(s) here
            .allowedMethods("GET, POST") // put the http verbs you want allow
            .allowedHeaders("Authorization") // put the http headers you want allow
    }
}

Ответ 2

У меня был успех с этим настраиваемым фильтром:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import reactor.core.publisher.Mono;


@Configuration
public class CorsConfiguration {

  private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN";
  private static final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
  private static final String ALLOWED_ORIGIN = "*";
  private static final String MAX_AGE = "3600";

  @Bean
  public WebFilter corsFilter() {
    return (ServerWebExchange ctx, WebFilterChain chain) -> {
      ServerHttpRequest request = ctx.getRequest();
      if (CorsUtils.isCorsRequest(request)) {
        ServerHttpResponse response = ctx.getResponse();
        HttpHeaders headers = response.getHeaders();
        headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
        headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
        headers.add("Access-Control-Max-Age", MAX_AGE);
        headers.add("Access-Control-Allow-Headers",ALLOWED_HEADERS);
        if (request.getMethod() == HttpMethod.OPTIONS) {
          response.setStatusCode(HttpStatus.OK);
          return Mono.empty();
        }
      }
      return chain.filter(ctx);
    };
  }

}

и org.springframework.boot:spring-boot-starter-web не следует включать в качестве зависимости - фильтр не работает с ним.

Ответ 3

@Configuration
public class WebFluxConfig {

    @Bean
    public WebFluxConfigurer corsConfigurer() {
        return new WebFluxConfigurerComposite() {

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("*")
                        .allowedMethods("*");
            }
        };
    }
}

который соответствует:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {

        @Override
        public void addCorsMappings(CorsRegistry registry) {

для весны mvc.

Ответ 4

Благодаря @Dachstein замена WebMvc-конфигураций на Webflux - правильный способ добавления глобального CORS Config здесь.

@Configuration
@EnableWebFlux
public class CORSConfig implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("*");
    }
}

Ответ 5

Вот ссылка на официальную документацию

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-cors

Есть 3 основных варианта

1) Использование аннотации @CrossOrigin на контроллере отдыха - ее можно использовать на уровне класса и/или метода

2) Реализуйте метод addCorsMapping из WebFluxConfigurer - он дает вам возможность подключиться к глобальному объекту CorsRegistry

3) Определить компонент CorsWebFilter - хороший выбор для функциональных конечных точек

Пожалуйста, посмотрите на документы, они хорошо объяснены.

Лично я использую третий вариант, когда хочу разрешить использование cors во время разработки, и я отделил бэкэнд от модуля frontend.

Представьте, что у вас есть webflux на бэкэнд-модуле, в то время как на внешнем интерфейсе у вас есть приложение реакции или угловое приложение. При разработке функций веб-интерфейса вам может потребоваться использовать webpack-dev-server для горячей перезагрузки, в то время как бэкэнд еще работает на netty - порт будет другим, и это вызовет проблему CORS. С третьим вариантом вы можете легко связать @Component с @Profile ("dev"), чтобы при развертывании в prod CORS были включены.

Ответ 6

Если кто-то хочет получить ответ Zufar на Kotlin (работает как шарм с функциями маршрутизации webflux), не разбираясь в том, как работают преобразования Kotlin SAM, вот код:

@Bean
fun corsFilter(): WebFilter {
    return WebFilter { ctx, chain ->
        val request = ctx.request
        if (CorsUtils.isCorsRequest(request)) {
            val response = ctx.response
            val headers = response.headers
            headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN)
            headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS)
            headers.add("Access-Control-Max-Age", MAX_AGE)
            headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS)
            if (request.method === HttpMethod.OPTIONS) {
                response.statusCode = HttpStatus.OK
                [email protected] Mono.empty<Void>()
            }
        }
        chain.filter(ctx)
    }
}

ОБНОВЛЕНИЕ Поскольку я начал проверять это, я нашел одну проблему с этим решением. Это нормально, если вы действительно хотите разрешить все методы. Но представьте, что вы хотите разрешить только POST и OPTIONS, например. И браузер пытается отправить PUT.

Тогда предпечатный ответ в основном скажет: "Эй, я могу обслуживать только POST и OPTIONS, но мой HTTP-статус будет в OK если вы дадите мне запрос с Access-Control-Request-Method=PUT ". Это должно быть 403 Forbidden однако. Более того, большинство из этих заголовков, таких как Access-Control-Allow-Methods следует добавлять только к предварительным запросам, а не ко всем запросам CORS. Решение:

@Bean
fun corsWebFilter(): CorsWebFilter {
    val corsConfig = CorsConfiguration()
    corsConfig.allowedOrigins = Arrays.asList(ALLOWED_ORIGINS)
    corsConfig.maxAge = MAX_AGE.toLong()
    //Notice it singular. Can't be comma separated list
    corsConfig.addAllowedMethod(ALLOWED_METHOD)
    corsConfig.addAllowedHeader(ALLOWED_HEADER)

    val source = UrlBasedCorsConfigurationSource()
    source.registerCorsConfiguration(MATCH_ALL_PATH_SEGMENTS, corsConfig)

    return CorsWebFilter(source)
}

где

const val MATCH_ALL_PATH_SEGMENTS = "/**"