본문 바로가기

IT/Spring

[Spring Boot] CORS 필터 설정하기

프로젝트 진행 중 아래와 같은 CORS 에러가 발생하여 이에 대한 해결 방법을 정리했습니다.

Access to XMLHttpRequest at '외부 API URL' from origin '외부 API를 호출한 URL' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
CORS란?
Cross-Origin Resource Sharing의 약자로 도메인이 다른 외부 서버 자원에 접근했을 때, 허용된 방식이 아닌 경우 CORS 에러가 발생합니다.

CORS 를 허용하는 설정 방법이 3가지가 있는 데, 이중 두가지 방법에 대해서 잘 적용되지 않아 filter를 직접 등록하는 방법으로 구현했습니다.

이유는 모르겠는데 아래 방법으로 설정했을 경우 잘 적용되지 않았습니다.
1. WebMvcConfigurer 인터페이스 구현을 통한 addCorsMappings 메소드 추가
2. 컨트롤러에 @CrossOrigin 어노테이션 추가

그래서 Filter 등록 방식으로 구현해보고자 합니다.
테스트하는 스프링 부트 버전, JDK 버전은 다음과 같습니다.
JDK 17
springframework.boot 2.6.7

1. CorsFilter를 컴포넌트로 등록한다

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
        ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
            "Origin, X-Requested-With, Content-Type, Accept, authorization");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }
}
response.setHeader("Access-Control-Allow-Origin", "*");
허용하고 싶은 도메인을 지정합니다. "*" 일 경우 모든 도메인에 대한 자원 접근을 허용합니다.

response.setHeader("Access-Control-Allow-Credentials", "true");
true로 설정하면 credentials를 이용한 요청을 처리할 수 있습니다.

response.setHeader("Access-Control-Allow-Methods", "*");
접근가능한 method를 지정합니다 (GET, POST, PATCH, PUT, DELETE)

response.setHeader("Access-Control-Max-Age", "3600");
preflight 요청에 대한 응답을 브라우저에서 얼마만큼 캐싱하고 있을지 설정할 때 사용합니다.

response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, authorization");
서버에서 허용하는 header의 key값을 정의합니다.