【问题标题】:Enable CORS in Spring 5 Webflux?在 Spring 5 Webflux 中启用 CORS?
【发布时间】:2018-04-09 06:44:17
【问题描述】:

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

我找不到任何合适的文档。

【问题讨论】:

标签: java spring cors spring-webflux


【解决方案1】:

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

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

【讨论】:

  • 对于 Spring WebFlux 中的非功能模型,如果使用 Netty 而没有经典的 servlet 过滤器并且不使用上述功能模型过滤器,那么推荐的实现过滤器功能的方法是什么?
  • @ROCKY,我在 netty 中检查了这个例子——它有效。我认为您可以在控制器中使用非功能模型并且它会起作用(但是还没有尝试过)。
  • 在netty中,这对我不起作用。 OPTIONS 仍然抛出 CORS 失败
  • 感谢您的回答,它拯救了我的一天。我在github.com/spring-cloud/spring-cloud-gateway/issues/112找到了这个链接
  • 这拯救了我的一天!谢谢
【解决方案2】:

这是使用 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
    }
}

【讨论】:

  • 这是我看到这个问题的唯一解决方案,但它对我不起作用。标头根本不会添加到响应中。这个被覆盖的方法被调用,如调试器所见。除了这个,你还有其他配置吗?
  • @haventchecked 你能解决这个问题吗?
  • 在使用 Spring Hateoas 和 @EnableHypermediaSupport 时不起作用 - 从 WebFluxConfigurer 扩展后不再添加链接。
【解决方案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) {

用于spring mvc。

【讨论】:

  • 感谢您的回复...我会在这个周末尝试。
  • 我已经用 spring-cloud-starter-gateway 尝试了你的答案(它使用 spring 5 webflux) - 没有成功
【解决方案4】:

如果有人想要 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
                return@WebFilter Mono.empty<Void>()
            }
        }
        chain.filter(ctx)
    }
}

更新 当我开始测试它时,我发现这个解决方案存在一个问题。如果你真的想允许所有方法也没关系。但是假设您只想允许 POSTOPTIONS,例如。并且浏览器正在尝试发送PUT

然后,预检响应基本上会说“嘿,我只能提供 POST 和 OPTIONS,但如果你给我一个带有 Access-Control-Request-Method=PUT 的请求,我的 HTTP 状态将是 OK”。但是应该是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 = "/**"

【讨论】:

    【解决方案5】:

    虽然@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;
        }
    

    【讨论】:

    • 这个对我有用,启用了 cors 身份验证。刚刚为标题添加了一行 configuration.setAllowedHeaders(List.of("*"));
    【解决方案6】:

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

    @Configuration
    @EnableWebFlux
    public class CORSConfig implements WebFluxConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedMethods("*");
        }
    }
    

    【讨论】:

      【解决方案7】:

      这里是官方文档的链接

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

      有 3 个主要选项

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

      2) 从 WebFluxConfigurer 实现 addCorsMapping 方法 - 它为您提供了一个进入全局 CorsRegistry 对象的钩子

      3) 定义一个 CorsWebFilter 组件 - 功能端点的好选择

      请看文档,有很好的解释。

      当我想在开发时允许 cors 并且我已经将后端与前端模块分离时,我个人使用第三个选项。

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

      【讨论】:

      【解决方案8】:

      如果在 sn-p 之后使用 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2019-04-24
        • 2021-02-27
        • 2020-05-01
        • 2021-08-17
        • 2018-12-12
        • 2018-04-15
        • 2021-04-09
        • 2020-10-24
        • 1970-01-01
        相关资源
        最近更新 更多