在Spring 5 Webflux中启用CORS?

时间:2017-10-27 15:39:57

标签: java spring cors spring-webflux

如何在Spring 5 Webflux项目中启用 CORS

我找不到任何适当的文件。

8 个答案:

答案 0 :(得分:21)

我使用此自定义过滤器取得了成功:

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不应作为依赖项包含在内 - 过滤器不适用于它。

答案 1 :(得分:8)

@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) {

for spring mvc。

答案 2 :(得分:6)

这是Webflux配置器的另一个解决方案。

附注:它的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
    }
}

答案 3 :(得分:1)

感谢@Dachstein,用Webflux替换WebMvc配置是在此处添加全局CORS配置的正确方法。

@Configuration
@EnableWebFlux
public class CORSConfig implements WebFluxConfigurer {

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

答案 4 :(得分:1)

虽然@Dachstein的答案是正确的,但如果启用了“安全性”,它仍然可能无法工作。您可以在https://docs.spring.io/spring-security/site/docs/current/reference/html5/#cors处阅读有关此文档的信息,但是由于缺少applyPermitDefaultValues()方法,提供的代码可能不够。

如果是这样,请尝试以下代码:

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.applyPermitDefaultValues();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:8081"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

答案 5 :(得分:0)

这是官方文档的链接

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

有3个主要选项

1)在rest控制器上使用@CrossOrigin注释-可以在类和/或方法级别使用它

2)从WebFluxConfigurer中实现addCorsMapping方法-它使您可以钩住全局CorsRegistry对象

3)定义CorsWebFilter组件-功能端点的不错选择

请看一下文档,有充分的解释。

我个人希望在开发过程中允许使用cors,并且已将后端与前端模块分离时,使用了第三个选项。

想象一下,在后端模块上有webflux,而在前端上有react或angular应用程序。在开发前端功能时,您可能想使用webpack-dev-server进行热重装,同时仍在netty上运行后端-端口将有所不同,这将导致CORS问题。使用第三个选项,您可以轻松地将@Component链接到@Profile(“ dev”),以便在产品中部署时启用CORS。

答案 6 :(得分:0)

如果有人想要Kotlin版本的Zufar的答案(像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
                return@WebFilter Mono.empty<Void>()
            }
        }
        chain.filter(ctx)
    }
}

更新 在开始测试时,我发现此解决方案存在一个问题。如果您确实想允许所有方法,也可以。但是假设您只想允许POSTOPTIONS。浏览器正在尝试发送PUT

然后,飞行前响应基本上会说:“嘿,我只能提供POST和OPTIONS,但是如果您通过OK向我发送请求,我的HTTP状态将为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's 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 = "/**"

答案 7 :(得分:0)

如果使用 spring webflux security 以下代码段有效

protected ServerHttpSecurity applyCors(ServerHttpSecurity http) {
    return http.cors().configurationSource(urlBasedCorsConfigurationSource()).and();
}

private UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource() {
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.applyPermitDefaultValues();
    // corsConfiguration.setAllowCredentials(true);
    corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
    corsConfiguration.setAllowedMethods(Arrays.asList("*"));
    corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
    UrlBasedCorsConfigurationSource ccs = new UrlBasedCorsConfigurationSource();
    ccs.registerCorsConfiguration("/**", corsConfiguration);
    return ccs;
}