Spring Cloud Gateway CORS 문제

알파로그·2023년 6월 28일
0

Error

목록 보기
31/37
post-custom-banner

✏️ 발단

  • MSA 를 적용시키기 위해서 프론트 개발자를 구하고 프론트단에서 백 서버로 api 요청을 보내니 CORS 문제가 발생했다.
    • Spring Cloud Gateway 는 CORS 요청을 디폴트로 막는다.
  • CORS 는 브라우저 쪽에서 백 서버로 요청을 보낼 때 발생되는 문제기 때문에 포스트맨으로 정상적으로 작동된다해도 문제가 발생하게 된다.

Access to XMLHttpRequest at 
    'http://101.101.208.240:8081/api/member/v1/create' 
    from origin 'http://localhost:3000/' has been blocked by CORS policy: 
    Response to preflight request doesn't pass access control check: 
    It does not have HTTP ok status.

🔗 CROS 란?

✏️ 문제 해결

📍 Spring Cloud Gateway 에서의 CORS 단순 요청 설정

🔗 Spring Cloud Gateway 공식 문서

  • application yml 에서 글로벌 설정을 해줄 수 있다.
    • 공홈의 예제에서는 모든 GET 요청을 허용하는 설정을 보여준다.
      • 다른 메서드도 추가하고 싶다면 GET 밑에 동일한 폼으로 메서드를 추가해주면 되는 것 같다.
    • https://docs.spring.io 대신 프론트의 도메인을 적으면 된다고 한다.
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

📍 Spring Cloud Gateway 에서의 CORS 사전 요청 설정

  • 단순 요청 설정만 해줄 경우 사전요청을 서버로 보내지 않고 바로 리턴 시킨다고 한다.
    • 즉, Response 에 포함되어있어야 할 Access-Control-Allow-Origin 이 헤더에 포함되지 않아서 CORS 에러가 발생하고 만다.
  1. application 환경설정 방식
    • allowedMethodsOPTIONS 를 추가한다.
    • JWT 를 사용할 경우 Access-Control-Allow-Credentials:true 를 추가해야한다.
      • 이때 allowed credentialstrue 인 경우, allowed_origin을 *로 입력할 수 없기 때문에 http://localhost:3000 이렇게 특정 origin을 입력해줘야한다.
spring:
  cloud:
	  gateway:
	    default-filters:
	      - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials 
	    globalcors:
	      cors-configurations:
	        '[/**]':
	          allowedOrigins: 'http://localhost:3000'
	          allow-credentials: true # JWT 나 쿠키를 사용해 메시지를 보내야 할 경우 true
	          allowedHeaders: '*'
	          allowedMethods: # 메서드를 명시하지 않으면 안되는 경우도 있기 때문에 메서드는 명시해주는 편이 좋다고 한다.
	          - PUT
	          - GET
	          - POST
	          - DELETE
	          - OPTIONS
  1. Configuration 객체 생성해서 설정
  • application 에서 환경설정 하는 방식 외에도 직접 객체를 생성해 설정하는 방식도 있다.
    • 효과는 동일하기 때문에 두가지 방법중 편한 방법으로 설정해주면 된다.
  • 이곳에서 allowed credentialstrue 로 설정할 수 있다.
    • 반대로 false 로 설정한다면 * 로 모든 경로의 요청을 허가할 수 있다.
@Configuration
public class PreFlightCorsConfiguration {
		
		private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type";
		private static final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
		private static final String ALLOWED_ORIGIN = "http://localhost:3000";
		private static final String MAX_AGE = "3600";

    // true 로 설정할 경우 allowed_origin 에 '*' 을 입력할 수 없고,
    //http://localhost:3000 이렇게 특정해줘야 한다.
		private static final String ALLOWED_CREDENTIALS = "true";

		
		@Bean
		public WebFilter corsFilter() {

				return (ServerWebExchange ctx, WebFilterChain chain) -> {

						ServerHttpRequest request = ctx.getRequest();

						if (CorsUtils.isPreFlightRequest(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);
								headers.add("Access-Control-Allow-Credentials",ALLOWED_CREDENTIALS);
				
								if (request.getMethod() == HttpMethod.OPTIONS) {
										response.setStatusCode(HttpStatus.OK);
										return Mono.empty();
								}
						}
						return chain.filter(ctx);
				};
		}
}

⚠️ 또다른 문제 발생

  • 위의 설정을 완료했음에도 불구하고 CORS 이슈가 해결되지 않는다.
    • 문제를 해결해 보려고 CORS 를 설정하는 여러가지 방식을 시도해 봤지만 문제가 전혀 해결되지 않았다.
  • 해결
    • 확인해보니 api 요청을 Gateway 를 통하지 않고 마이크로 서버에 다이렉트로 요청을 해서 발생한 문제였다.
    • Gateway 를 통하도록 url 을 수정하니 문제가 해결되었다.
profile
잘못된 내용 PR 환영
post-custom-banner

0개의 댓글