Spring MVC에서 CORS이슈 해결

Review/디버깅

Spring MVC에서 CORS이슈 해결

조커린 2021. 6. 11. 00:46

어쩌다보니 Spring MVC 서버를 이용해 REST API서버를 만들고 있는데

이러다 보니 쓸 수 있는 디펜던시가 매우 제한적이고 불편하긴 하더라

아무래도 리액트와의 연동은 부트와 하는 편이 많으니....

 

Spring에서 CORS에러는 Spring Security의 Cors를 이용해서 CSRF 공격 방어와 동시에 해결이 가능한 줄만 알았는데

Spring에서 설정파일의 CORS옵션을 제대로 못 읽는 문제 등이 발생해 response header를 Filter단에서 request값을 이용해 직접 설정을 해주었다. 

 

React단의 오류에서 힌트를 얻었다. access-Control-Allow-origin header의 값이 세팅이 되지 않았다고 하면서 거기에 세팅 되어져 있는 값까지 뜨는데 자꾸 localhost:3000/이런식으로 뜨는 것이다...;; 아니 localhost:3000/맞거든?

 

진리는 모질라 문서 아닌가? 검색했더니 모질라 문서 나오길래 바로 접속했더니 

 

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Allow-Origin

 

Access-Control-Allow-Origin - HTTP | MDN

Access-Control-Allow-Origin 응답 헤더는 이 응답이 주어진 origin으로부터의 요청 코드와 공유될 수 있는지를 나타냅니다.

developer.mozilla.org

가능한 Access-Control-Allow-Origin 값을 허용된 origin 집합으로 제한하는 것은 요청 헤더의 Origin를 검사하는 서버 측 코드가 필요합니다. 이를 허용된 origin 리스트와 비교하고,  Origin 값이 리스트에 있으면 Access-Control-Allow-Origin 값을 Origin과 동일한 값으로 설정합니다.

오호... 근데 여기까진 내가 알고있는 내용과 같았다. 

근데 지금까지 외부 디펜던시를 이용해서 cors를 해결하다가 직접 헤더값을 설정하면 되는거 아닌가 싶어서 밑으로 내렸더니...

바로 자바 코드가 딱!!!!

 

 

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
public class SimpleCORSFilter implements Filter {

private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);

public SimpleCORSFilter() {
    log.info("SimpleCORSFilter init");
}

@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", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}

}

 

와 request에서 header의 origin 값만 가지고 와서 설정을 해주면 되는구나 싶어서 바로 설정했더니 해결됐다.

라이브러리 안쓰고 직접 설정해본건 처음이라 감명깊었다...

 

스프링 경력 엄청 오래되신 대선배님께 여쭤봤는데, 

보통은 시큐리티는 다른 용도로 많이 쓰시고 (좀 더 보안쪽으로 다룰 때)

이런 식으로 직접 헤더를 정확하게 앞단과 맞물릴 수 있도록 설정한다고 하셨다. 

정확한 자원의 Origin 을 써주는 것이 중요한 것 같다. 

참고로 header의 origin 은 fetch 가 시작되는 위치라고 한다. 

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Origin