이 글을 남기는 이유는,
JWT 검증을 수행하는 Interceptor에 의해서 다른 출처(다른 서버)에서의 XHR Request의 OPTIONS로 Request 허용 여부를 먼저 확인하는 preFilght Request가 충돌하는 상황을 길록하기 위해서다.
나의 상황은 아래와 같았다.
먼저 CORS 정책을 제공하는 CORSFilter를 Tomcat 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 검증을 수행하는 Interceptor를 DistpatcherServlet의 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 Filter가 Interceptor가 구동되는 시점인 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);
Interceptor는 Request의 Header에 있는 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를 전송 전에,
preFlight로 OPTIONS Http Method로 Reqeust가 허용 가능한지 확인을 수행하는데,
이 preFlight Request 역시 CORS Filter의 .doFilter() 후에 Interceptor의 검증 로직에 걸리게 되고,
이때 Authorization은 preFlight Request에 아직 허용되지 않은 Header여서 전송될 수 없었고,
preFlight Request가 실패하여 최종 XHR Requeset가 Fail 되었던 것이다.
그림을 통해 보면 아래와 같은 상황이었다.

JWT 검증을 수행하는 Interceptor에 Request의 Method가 preFlight 용 OPTIONS일 경우,
검증을 수행하지 않는 로직을 추가해주었다.
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;
}
}
이를 통해 문제를 해결할 수 있었다.
오늘도 해결 완료! :) 🙆♀️