SpringBoot에서 CORS할 때 header, preflight 이슈 해결하기

Jaewon Oh·2020년 3월 8일
7
post-custom-banner

1. CORS 이슈 및 해결

스터디 프로젝트에서 화면(client)은 React로, 서버(server)는 Spring Boot으로 개발하고 있다.
다양한 이슈로 인해 화면 단 서버를 Node로 띄우고 있다. 따라서 CORS(Cross-Origin Resource Sharing, CORS) 이슈가 발생하여 Spring Boot에 다음과 같은 처리를 하였다.

Java 코드


@Configuration
public class WebMvcConfig implements WebMvcConfigurer {	
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    	registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000", "http://35.222.169.XX:9000");

    }
}



2-1. CORS response header 이슈

하지만 JWT(JSON Web Token)을 적용하는 과정에서 서버 단에서 response header에 값을 설정하고, 화면 단에서 읽는 과정에서 값을 읽지 못하는 현상(null 값으로 반환됨)이 발생하였다.

Java 코드


	response.setHeader("jwt-token", "token value");

JavaScript 코드


	fetch("/user/login", oOption).then((response) => {
		// not "token value", but null
		var token = response.headers.get("jwt-token");
	});


2-2. CORS response header 이슈 해결 방법

구글링을 해보니 CORS의 경우 기본적으로 화면에서 response header 값을 읽지 못한다고 한다. (개발자도구 네트워크 탭에서는 확인 할 수 있음.. JavaScript 코드에서 읽을 수 없음)

좌절하고 response body에 값을 넣으려다 조금 더 찾아보니 addCorsMappings에서 다음을 추가하면 화면에서 지정된 header 값("jwt-token")은 읽을 수 있다고 하여 추가하였고, 화면에서 값을 읽을 수 있게 되었다.

Java 코드


@Configuration
public class WebMvcConfig implements WebMvcConfigurer {	
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    	registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000", "http://35.222.169.XX:9000")
                .exposedHeaders("jwt-token")	//make client read header("jwt-token")
                ;

    }
}

  • .exposedHeaders("jwt-token")

JavaScript 코드


	fetch("/user/login", oOption).then((response) => {
		// return "token value"
		var token = response.headers.get("jwt-token");
	});



3-1. CORS preflight 이슈

구글링을 해보니 CORS 시 browser에서 API를 받는 서버가 요청을 받을 수 있는지 option 메소드를 통해 먼저 서버에 호출한다고 한다. 그런데 해당 요청을 보낼 때 request header에 실어보낸 JWT를 받지 못하여 다음과 같은 문제가 발생하였다.

browser console error


Access to fetch at 'http://localhost:9090/user/jwt-auth/tokeninfo' 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.


3-2. CORS preflight 이슈 해결 방법

따라서 JWT를 체크하는 부분에서 request method가 OPTIONS일 경우 JWT를 체크하지 않는 방향으로 문제를 해결하게 되었다.


@Component
public class JwtInterceptor extends HandlerInterceptorAdapter {
	Logger logger = LoggerFactory.getLogger("io.ojw.mall.interceptor.JwtInterceptor");
	
	private static final String TOKEN = "jwt-token";

	private JwtService jwtService;
	
	public JwtInterceptor(JwtService jwtService) {
		this.jwtService = jwtService;
	}
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		final String token = request.getHeader(TOKEN);
		
		logger.debug("JwtInterceptor > preHandle > token: " + token);
		
		if (StringUtils.equals(request.getMethod(), "OPTIONS")) {
			logger.debug("if request method is options, return true");
			
			return true;
		}
		
		if(token != null && jwtService.checkToken(token)){
			return true;
		}else{
			throw new UnauthorizedException();
		}
	}
}

profile
Web SI Developer
post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 4월 19일

좋은 내용 잘 보고 갑니다!!! 감사합니다.

답글 달기
comment-user-thumbnail
2023년 8월 30일

고맙습니다.. 덕분에 잘 해결되었습니다

답글 달기