본문 바로가기
DDD&MSA

[Spring Cloud Gateway] 여러 도메인에 대해 CORS 설정하기

by 덩라 2023. 12. 24.

0. API Gateway 에서의 CORS 설정

현재 개발 중인 프로젝트의 백엔드 서버는 MSA 구조로 개발되어 있어서, 프론트엔드 서버의 요청을 아래와 같은 흐름으로 받아들이고 있습니다.

클라이언트의 요청을 API Gateway 가 받아서, URI 를 확인해서 적절한 마이크로 서비스로 요청을 라우팅하는 형태입니다.

이 때, API Gateway는 클라이언트 요청에 대해 CORS 설정을 추가해야 합니다.

CORS 에 대한 내용은 아래 포스팅을 참고해주세요.
https://byunsw4.tistory.com/22
 

Access to XMLHttpRequest at 'http://localhost:8888/api/v1/login' from origin 'http://localhost:3000' has been blocked by CORS po

아래 환경에서 개발하다가 로그인 기능을 테스트하는 단계에서 발생한 오류입니다. Front-End : React (axios 사용) 3000번 포트 서비스 Back-End : Java / Spring 8888 포트 서비스 위 에러가 발생한 원인은 웹

byunsw4.tistory.com

 

API Gateway 에 클라이언트 요청에 대한 CORS설정을 추가하게 된다면, 아래와 같은 흐름으로 요청이 흘러가게 됩니다.

위 같은 형태를 설정하기 위해, Spring Cloud Gateway 에선 어떻게 CORS 를 적용하는지 알아보았습니다.

 

1. Spring Cloud Gateway 에서 전체적으로 CORS 적용

현재 개발 중인 프로젝트는 Spring Cloud 기반으로 MSA 구조가 구현되어 있기 때문에, API Gateway 역할을 Spring Cloud Gateway 를 사용합니다.

Spring Cloud Gateway 에서는 아래와 같이 CORS 를 설정하도록 가이드하고 있습니다.

https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/cors-configuration.html

 

CORS Configuration :: Spring Cloud Gateway

You can configure the gateway to control CORS behavior globally or per route. Both offer the same possibilities.

docs.spring.io

 

위 설정을 제 API Gateway 프로젝트에 적용했을 때, 아래와 같이 적용되었습니다.

# application.yml
spring:
  config:
    activate:
      on-profile: local

  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allow-credentials: true
            allowed-origins: "http://localhost:3000"
            allowed-headers: "*"
            allowed-methods:
              - PUT
              - GET
              - POST
              - DELETE
              - OPTIONS

 

Spring Cloud 는 내부적으로 요청 URI 에 대한 CORS 옵션을 Map 형태로 저장합니다.

고로 위 설정은, 모든 URI 요청 (/**) 에 대해 아래와 같은 옵션을 적용하는 설정입니다.

  1. http://localhost:3000 으로의 요청은 모두 허용한다.
  2. 모든 Request Header 값을 허용한다.
  3. PUT / GET / POST / DELETE / OPTIONS 로 온 요청은 허용한다.

 

2. 여러 도메인에 CORS global 적용하기

API Gateway 는 클라이언트의 요청이 통과하는 관문과 같은 역할을 수행하기 때문에, 많은 클라이언트의 요청이 집중될 수 밖에 없습니다.

그 클라이언트는 같은 시스템으로써 서비스되는 프론트엔드 혹은 모바일 서버일 수 도 있고, 다른 외부 시스템일 수 도 있습니다.

즉, 모든 클라이언트가 서비스하는 도메인이 다 다를 경우, API Gateway 는 이에 대해 CORS 를 적용해주어야 합니다.

 

Spring Cloud 가 어떻게 Global CORS 를 등록하는지, 찾아보던 중 아래 코드를 찾을 수 있었습니다.

```GatewayAutoConfiguration.java
@Configuration(proxyBeanMethods = false) // 여러 annotation 이 있지만, 나머진 생략
public class GatewayAutoConfiguration {
    // 중략
    @Bean
    public GlobalCorsProperties globalCorsProperties() {
        return new GlobalCorsProperties();
    }
    // 중략
}

```GlobalCorsProperties.java
@ConfigurationProperties("spring.cloud.gateway.globalcors")
public class GlobalCorsProperties {

	private final Map<String, CorsConfiguration> corsConfigurations = new LinkedHashMap<>();

	public Map<String, CorsConfiguration> getCorsConfigurations() {
		return corsConfigurations;
	}

}

```CorsConfiguration.java
public class CorsConfiguration {
    // 중략

    @Nullable
    private List<String> allowedOrigins;
    
    // 중략
}

의미를 대략 요약하자면, 다음으로 해석됩니다.

  1. GatewayAutoConfigration.java 가 @Configuration 에 의해, @Bean 이 붙은 GlobalCorsProperties를 스프링 Bean 으로 등록한다.
  2. GlobalCorsProperties.java 는 @ConfigurationProperties("spring.cloud.gateway.globalcors") 에 의해 properties 파일(application.properties 혹은 application.yml) 내에 spring.cloud.gateway.globalcors 하위에 정보Map<String, CorsConfiguration> 형태로 생성한다.
  3. CorsConfiguration 이 생성되면서, properties 파일의 allowedOrigins 의 값을 List 로 저장한다.

 

위 과정을 미루어 봤을 때, 공식문서에 나와있진 않지만 yml 설정의 value 가 List 로 인식되는 형태로 설정하면 된다는 것을 알 수 있습니다.

#application.yml
spring:
  config:
    activate:
      on-profile: local

  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allow-credentials: true
            # 이것도 가능
            #allowed-origins: "http://localhost:3000, http://localhost:3001"
            allowed-origins:
              - http://localhost:3000
              - http://localhost:3001
            allowed-headers: "*"
            allowed-methods:
              - PUT
              - GET
              - POST
              - DELETE
              - OPTIONS

 

yml 파일 문법 참고 : https://namu.wiki/w/YAML
 

YAML

기존에 주로 사용되던 포맷인 JSON 의 불편함을 해소하기 위해 만들어진 superset 이다. 즉 일반적인 j

namu.wiki

 

댓글