[Spring] CORS preFlight(OPTIONS Method) Interceptor 검증 로직 제외해주기(Access to XMLHttpRequest at '' from origin '' has been blocked by CORS policy)

GilLog·2021년 7월 22일
0

에러

목록 보기
17/17
post-custom-banner

이 글을 남기는 이유는,

JWT 검증을 수행하는 Interceptor에 의해다른 출처(다른 서버)에서의 XHR RequestOPTIONS로 Request 허용 여부를 먼저 확인하는 preFilght Request충돌하는 상황을 길록하기 위해서다.

문제 상황

나의 상황은 아래와 같았다.

먼저 CORS 정책을 제공하는 CORSFilterTomcat Server Configure 인 web.xml에,

public class SimpleCORSFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
		httpResponse.setHeader("Access-Control-Max-Age", "3600");
		httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type, Authorization");
		httpResponse.setHeader("Access-Control-Allow-Origin", "*");
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig filterConfig) {
		// Do nothing
	}

	@Override
	public void destroy() {
		// Do nothing
	}
}

JWT 검증을 수행하는 InterceptorDistpatcherServlet의 Configure인 servlet-context.xml에 등록해두었다.

public class JwtInterceptor extends HandlerInterceptorAdapter {
	private static final Logger LOG = Logger.getLogger(JwtInterceptor.class);
	@Autowired
	private AuthService authService;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception, JwtException {
		String jwt = request.getHeader("Authorization");
		if (jwt == null) {
			throw new AuthenticationException("JWT is null");
		}
		try {
			authService.vertifyJwt(jwt);
		} catch (JwtException e) {
			LOG.error("[JwtInterceptor] JwtException Throw");
			throw e;
		}
		return true;
	}
}

그 후 동일 출처인(Swagger UI)에서 API 테스트를 수행하다.

다른 서버에서 최종 테스트를 해보려는데,

아래와 같이 CORS Policy 관련 XHR Request 실패 메시지가 발생했다.

Access to XMLHttpRequest at 'https://api.gillog.com:87/notices' 
from origin 'https://gillog.com:84' 
has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
It does not have HTTP ok status.

나는 최초에 CORS FilterInterceptor가 구동되는 시점인 DispatcherServlet으로 Request가 오기전 Server 단에서 처리되어,

문제가 발생하지 않을거라 생각했다.

문제 원인

CORS Filter에서는 아래의 Authorization Header를 Allow 해준다는 Response를 Header에 지정해준다.

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
		httpResponse.setHeader("Access-Control-Max-Age", "3600");
                // Authorization Allow
		httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, content-type, Authorization");
		httpResponse.setHeader("Access-Control-Allow-Origin", "*");
		chain.doFilter(request, response);

InterceptorRequestHeader에 있는 Authorization의 값을 통해 검증을 수행한다.

	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception, JwtException {
		String jwt = request.getHeader("Authorization");
		if (jwt == null) {
			throw new AuthenticationException("JWT is null");
		}
		try {
			authService.vertifyJwt(jwt);
		} catch (JwtException e) {
			LOG.error("[JwtInterceptor] JwtException Throw");
			throw e;
		}
		return true;
	}

결론부터 말하자면, 다른 출처의 자원 공유 정책(CORS)에서 실제 Request를 전송 전에,

preFlightOPTIONS Http Method로 Reqeust가 허용 가능한지 확인을 수행하는데,

preFlight Request 역시 CORS Filter.doFilter() 후에 Interceptor의 검증 로직에 걸리게 되고,

이때 AuthorizationpreFlight Request에 아직 허용되지 않은 Header여서 전송될 수 없었고,

preFlight Request가 실패하여 최종 XHR Requeset가 Fail 되었던 것이다.

그림을 통해 보면 아래와 같은 상황이었다.

문제 해결

JWT 검증을 수행하는 InterceptorRequestMethodpreFlightOPTIONS일 경우,

검증을 수행하지 않는 로직을 추가해주었다.

public class JwtInterceptor extends HandlerInterceptorAdapter {
	private static final Logger LOG = Logger.getLogger(JwtInterceptor.class);
	@Autowired
	private AuthService authService;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception, JwtException {
                // Request의 Method가 OPTIONS 인 경우 통과
		if (request.getMethod().equals("OPTIONS")) {
			return true;
		}
		String jwt = request.getHeader("Authorization");
		if (jwt == null) {
			throw new AuthenticationException("JWT is null");
		}
		try {
			authService.vertifyJwt(jwt);
		} catch (JwtException e) {
			LOG.error("[JwtInterceptor] JwtException Throw");
			throw e;
		}
		return true;
	}
}

이를 통해 문제를 해결할 수 있었다.

오늘도 해결 완료! :) 🙆‍♀️

profile
🚀 기록보단 길록을 20.10 ~ 22.02 ⭐ Move To : https://gil-log.github.io/
post-custom-banner

0개의 댓글