spring-cloud / spring-cloud-gateway

An API Gateway built on Spring Framework and Spring Boot providing routing and more.
http://cloud.spring.io
Apache License 2.0
4.52k stars 3.32k forks source link

spring cloud gateway version 3 CORS Origin policy problem can't be modify #2946

Closed SubhamKrGuptaDev closed 7 months ago

SubhamKrGuptaDev commented 1 year ago

I think this is a bug because I tried every solution that I get on the internet but it does not work. still CORS Origin policy error I'm getting

It always shows a CORS origin problem or 403 error but in Postman works perfectly.

If you know the solution please reply or else please fix this bug I think this is a bug or I'm going something wrong

application.yml file

server:
  port: 9999

spring:
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true

        corsConfigurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
              - PATCH
            allowedHeaders:
              - "Origin"
              - "Content-Type"
              - "Accept"
              - "Authorization"
              - "User-Key"
              - "Request-Tracker"
              - "Session-Tracker"
              - "X-XSRF-TOKEN"
              - "X-IBM-CLIENT-ID"
              - "Message-ID"
              - "X-IBM-CLIENT-SECRET"
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_FIRST

      routes:
        - id: ADMIN-SERVICE
          uri: https://example
          predicates:
            - Path=/v1.0.0/registration/example

        - id: ADMIN-SERVICE
          uri:  https://example
          predicates:
            - Path=/v1.0.0/registration/example/**
          filters:
            - AuthenticationFilter

      httpclient:
        ssl:
          useInsecureTrustManager: true

AuthenticationFilter.java

package com.api.filter;

import com.api.exception.MissingAuthorizationHeaderException;
import com.api.exception.UnauthorizedAccessException;
import com.api.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Slf4j
@Component
public class AuthenticationFilter extends AbstractGatewayFilterFactory<AuthenticationFilter.Config> {

    @Autowired
    private RouteValidation routeValidation;

    @Autowired
    private JwtUtil jwtUtil;

    public AuthenticationFilter() {
        super(Config.class);
        log.info("AuthenticationFilter() -> | ");
    }

    @Override
    public GatewayFilter apply(Config config) {

        log.info("============== Apply Method Start ==============");
        log.info("apply(Config) -> | Config : {}", config);

        GatewayFilter bearer = (exchange, chain) -> {

            log.info("apply(Config) -> | Exchange : {} | Chain : {}", exchange, chain);

            if (routeValidation.isSecured.test(exchange.getRequest())) {
                log.info("apply(Config) -> | Route Validation isSecured : ");
                //header contains token or not
                log.info("apply(Config) -> | HttpHeader Check : {}", HttpHeaders.AUTHORIZATION);

                if (!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                    log.error("apply(Config) -> | MissingAuthorizationHeaderException Throw :");
                    throw new MissingAuthorizationHeaderException();
                }

                log.info("apply(Config) -> | authorization header present");
                String authHeader = exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
                log.info("apply(Config) -> | AuthHeader : {}", authHeader);

                if (authHeader != null && authHeader.startsWith("Bearer ")) {
                    authHeader = authHeader.substring(7);
                    log.info("apply(Config) -> | After Delete AuthHeader : {}", authHeader);
                }

                try {

                    log.info("apply(Config) -> | Try to validateToken");
                    jwtUtil.validateToken(authHeader);

                } catch (Exception e) {
                    log.error("apply(Config) -> | Exception Message : {} | Exception Cause : {}", e.getMessage(), e.getCause());
                    log.error("apply(Config) -> | UnauthorizedAccessException Throw | invalid access...");
                    throw new UnauthorizedAccessException();
                }

            }

            Mono<Void> filter = chain.filter(exchange);
            log.info("apply(Config) -> | Mono<Void> : {}", filter);

            return filter;
        };

        log.info("apply(Config) -> | GatewayFilter Object : {}", bearer);
        log.info("============== Apply Method End ==============");
        return bearer;
    }

    public static class Config {
        public Config() {
            log.info("Config() -> | Create Object Config class of sub class AuthenticationFilter extends by AbstractGatewayFilterFactory");
        }
    }

}
ksilz commented 1 year ago

We had the same issue in our project. No matter what we try, our requests get always rejected because of CORS.

ksilz commented 1 year ago

@SubhamKrGuptaDev I think you're missing the OPTIONS method. With CORS, the browser sends a so-called preflight request. That's an OPTIONS request.

polster commented 1 year ago

Very similar observation(s) here at my end - Looks like globally defined CORS policy applies to dynamically specified routes (both in an application yaml file), where the same does not apply to our REST Controller(s) within the same application...

Only workaround so far that seems to work, is when I use the @CrossOrigin annotation directly on Controller Class level, resp. as described here: https://www.baeldung.com/spring-webflux-cors.

So now I'm really not sure if there is a bug or if the observed behavior is by intention - was able to reproduce in both Spring Cloud release train 2022 and 2021.

SubhamDeveloperGupta commented 1 year ago

The Issue is Version Version is 3.0 and the API gateway 3.0 version has some bugs if you want to use API Gateway then the below 3.0 versions are working fine you can try it once.

ducanh2110 commented 1 year ago

any news on this topic? I have the same problems

n0rb33rt commented 1 year ago

I have fixed it! Now it works !!!! Just copy it in order:

server:
  port: 2620
  address: 25.68.201.55
eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:8761/eureka
spring:
  application:
    name: Api GateWay
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        corsConfigurations:
          '[/**]':
            allowedOrigins: "http://127.0.0.1:5500"
            allowedHeaders:
              - "Origin"
              - "Content-Type"
              - "Accept"
              - "Authorization"
              - "Referer"
            allowedMethods:
              - POST
              - GET
              - OPTIONS
      routes:
        - id: Customer Login
          uri: http://localhost:8080
          predicates:
            - Path=/api/v1/auth/login
        - id: Customer Registration
          uri: http://localhost:8080
          predicates:
            - Path=/api/v1/auth/register
        - id: Customer Google login
          uri: http://localhost:8080
          predicates:
            - Path=/api/v1/auth/google/login
        - id: Confirm email
          uri: http://localhost:8081
          predicates:
            - Path=/confirm
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_FIRST
StevenPG commented 10 months ago

@n0rb33rt are you using latest spring-boot 3.2.0 and spring cloud 2023.0.0 with this working? What version was this successful with?

hannah23280 commented 10 months ago

I also encounter same issue with the below setting. 7 months has passed, no engineer is assigned to look at this issue? Currently using spring boot 3.2.1

spring:
  cloud:
    gateway:
       routes:
        - id: multiplication
          uri: http://localhost:8080/
          predicates:
            - Path=/challenges/**,/attempts,/attempts/**,/users/**
        - id: gamification
          uri: http://localhost:8081/
          predicates:
            - Path=/leaders
       globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "http://localhost:3000"
            allowedHeaders: "*"
            allowedMethods:
              - "GET"
              - "POST"
              - "OPTIONS"
       default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE
hannah23280 commented 10 months ago

I also notice that in 3.2.1, the starter is org.springframework.cloud:spring-cloud-starter-gateway-mvc In 3.1.7, it is org.springframework.cloud:spring-cloud-starter-gateway (without the -mvc)

Not sure if this difference is related to the CORS origin issue..

abhishekchatterjee-rss commented 9 months ago

I faced the same issue, but as n0rb33rt mentioned the below configuration worked for me, add-to-simple-url-handler-mapping: true As also mentioned in Spring Doc

mathias8dev commented 9 months ago

@hannah23280 It works with spring boot 3.2.1 Do not enable cors on your microservices. Just enable it on the gateway.

spencergibb commented 7 months ago

It looks like things have been resolved. Feel free to comment if not and we can reopen to discuss.

MateoRodriguez0 commented 5 months ago

@hannah23280Funciona con Spring Boot 3.2.1. No habilite cors en sus microservicios. Simplemente habilitelo en la puerta de enlace. Ugh, thank you very much because I didn't see this post before, the official documentation was always a little correct, in my case I only did this and don't enable @crossorigin for any microservices


spring:
  application:
    name: servicio-api-gateway
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        corsConfigurations:
          '[/**]':
            allowedOrigins: "http://127.0.0.1:5501"
            allowedHeaders: "*" 
            allowedMethods:
              - POST
              - GET
              - OPTIONS
              - PUT 
              - DELETE

server:
  port: 10450
JuanPabaz commented 3 months ago

I have this configuration, it works great with all the methods but delete, what can I add to this to make it work with the delete method: spring: application: name: msvc-gateway cloud: gateway: globalcors: add-to-simple-url-handler-mapping: true cors-configurations: '[/*]': allowed-origins: "" allowedMethods:

teyyub commented 3 months ago

is there anyone who says it is working does not share small code with us :)?

Mean-Machine-Dee commented 2 months ago

I tried using the configuration file method but it failed. However configuration via Bean works fine.

@Configuration
public class CorsConf extends CorsConfiguration {
    @Bean
    public CorsWebFilter corsFilter()
    {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials( true );
//        config.setAllowedOrigins( List.of( "*" ) ) //Collections.singtonList(....);
        config.setAllowedOriginPatterns(List.of( "*" ));
        config.setAllowedMethods( List.of( "GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD" ) );
        config.setAllowedHeaders( List.of( "origin", "content-type", "accept", "authorization", "cookie" ) );

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration( "/**", config );

        return new CorsWebFilter(source);
    }