簡體   English   中英

在 Spring 5 Webflux 中啟用 CORS?

[英]Enable CORS in Spring 5 Webflux?

如何在 Spring 5 Webflux 項目中啟用CORS

我找不到任何適當的文件。

我使用這個自定義過濾器取得了成功:

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不應作為依賴項包含在內 - 過濾器不適用於它。

這是 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
    }
}
@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。

如果有人想要 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,但我的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'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 = "/**"

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

感謝@Dachstein,用 Webflux 替換 WebMvc 配置是在此處添加全局 CORS 配置的正確方法。

@Configuration
@EnableWebFlux
public class CORSConfig implements WebFluxConfigurer {

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

這是官方文檔的鏈接

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。

如果使用 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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM