1

I've been searching on how to enable CORS when using Spring Cloud Gateway in addition with Eureka discovery.

My application is up and running and everything works fine. As I work with Eureka discovery I enabled automatic route discovery for Spring Cloud gateway with the following property in application.properties so I don't need to specify the (custom) routing myself.

spring.cloud.gateway.discovery.locator.enabled = true

I've searched to web to no avail on how to enable CORS, as it is very poorly documented at the moment. The only thing I could find is the following documentation: https://cloud.spring.io/spring-cloud-gateway/single/spring-cloud-gateway.html#_header_route_predicate_factory where it is mentiond in section 5.14 that some default security headers are applied and how to change them.

It says header X-Permitted-Cross-Domain-Policies is default set to none which means CORS is disabled.

The documentation tells me I can change this header by setting property in my application.properties file.

spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies = ?

But I have no idea to what value I need to set this property and it isn't documented anywhere. I have tried setting it to 'any', 'all' and '*' but with no luck.

Can someone help or does anybody know the answer to this? Or if i misinterpreted something please let me know.

3 Answers3

1

No,you can't set additional response headers when DiscoveryClient Route Definition Locator is enabled by spring.cloud.gateway.discovery.locator.enabled = true.

You should define your own route and add AddResponseHeader to filters in application.properties or application.properties,Here is an example for your reference.

spring:
  cloud:
      routes:
      - id: foo_service
        uri: lb://foo_service
        predicates:
        - Path=/foo_service/**
        filters:
        - AddResponseHeader=Access-Control-Allow-Origin, *
        - RewritePath=/foo_service/(?<segment>.*), /$\{segment}
chao_chang
  • 778
  • 8
  • 14
  • 1
    I have followed the same but it is not working for me. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8484' is therefore not allowed access. – GoutamS Sep 03 '18 at 20:10
  • Please Follow https://stackoverflow.com/questions/46978794/enable-cors-in-spring-5-webflux/47494858#47494858 – GoutamS Sep 03 '18 at 22:00
1

OK, its a bit late but i have an answer. Just put CORS as global Filter:

spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedOriginPatterns=*
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowCredentials=true
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedMethods=*
spring.cloud.gateway.globalcors.corsConfigurations.[/**].allowedHeaders=*

This is for application.properties but its the same way for yml.

Going a little deeper on CORS with eureka auto-discovery enable, it will give u a 404 without cors headers if your service is offline. It took me a while but i got to this code:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
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;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

@Component
public class CustomWebFilter implements WebFilter {

    private final static List<String> gateway404Headers = List.of("transfer-encoding", "Content-Type", "Content-Length");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        exchange.getResponse().beforeCommit(() -> {
            if(isBlockedByGateway(exchange.getResponse())) {
                addCors(exchange);
            }
            return Mono.empty();
        });
        return chain.filter(exchange);
    }

    private boolean isBlockedByGateway(ServerHttpResponse response) {
        return response.getStatusCode()== HttpStatus.NOT_FOUND && response.getHeaders().size()==3
                && checkHeaders(response.getHeaders());
    }

    private boolean checkHeaders(HttpHeaders headers) {
        AtomicBoolean allHeadersValid = new AtomicBoolean(true);
        headers.forEach((header, headerUtils) -> {
            allHeadersValid.set(allHeadersValid.get() && gateway404Headers.contains(header));
        });
        return allHeadersValid.get();
    }

    public void addCors(ServerWebExchange exchange) {
        if (CorsUtils.isCorsRequest(exchange.getRequest())) {
            HttpHeaders headers = exchange.getResponse().getHeaders();
            List<String> headerslist = exchange.getRequest().getHeaders().get("Origin");
            if(headerslist != null && headerslist.size() == 1) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, headerslist.get(0));
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            }
        }
    }
}

I dont think its a good solution though, at least not for my purpose, but migth be useful for someone.

0

Please refer below link, if your format in yml is wrong then correct it as per example shared. My problem got fixed by this change.

https://github.com/spring-cloud/spring-cloud-gateway/issues/1922

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 19 '22 at 09:56