일정 관리 및 공유 오피스 대여 서비스인 meeti 프로젝트를 진행하면서 배포 후 프런트 팀원과 테스트하는 도중, 한가지 문제를 만나게 되었습니다...!🧐
원인 분석 끝에 WebConfig
에 정의해두었던 HTTP Header Interceptor
에서 발생하는 문제임을 발견하였습니다.
따라서, 문제를 해결하는 과정 속에서 알게된 점들을 기록해두고자 글을 작성하게 되었습니다.
로그인 API를 실행하면 토큰이 발급됩니다.
발급된 accessToken
을 Header에 Authorization
의 Value로 적용한다면 로그인 처리가 완료됩니다.
따라서 accessToken
을 붙여 넣었는데...😳
분명 헤더에 값이 잘 들어가있음을 확인하였지만, 계속해서 Authorization Header
가 비어있다는 에러가 발생하였습니다.
따라서 에러를 해결해보고자 문제를 탐색해보았습니다.
바로 이 친구가 원인이었습니다! (잡았다 요놈)
이러한 현상은 왜 일어나는 것일까요?
Preflight request
는 CORS(자원 공유 정책) 에서 실제 요청을 보내기 전에 OPTIONS
HTTP Method로 요청이 허용되는지 확인하기 위해 Preflight request
를 우선적으로 전달한다고 합니다.
바로 사전 점검의 의미가 강하다는 것이죠.
하지만, Preflight request
가 아무리 사전 점검을 위한 요청이라 하더라도 request
임은 변함없기 때문에 WebConfig
의 Interceptor
에 걸리게 되었고, 결과적으로 Authorization Header
가 빈값으로 확인될 수 밖에 없던 것이었습니다. 😫
accessToken
검증을 위한 Interceptor
원인 파악을 하고 해당 API를 Interceptor
에 추가하여 실행하였더니 동작엔 이상없었습니다.
하지만 모든 요청에 대해 Interceptor
과정을 거치치 않는다면 그것 또한 문제임이 분명했습니다.
따라서, 기존 요청만을 받기 위해 Preflight request
를 걸러내는 방법을 사용하고자 하였습니다.
AuthenticationInterceptor
작성 코드 : Preflight request
를 걸러내지 못함위와 같은 상태에서 Preflight request
를 걸러내는 조건을 추가하였습니다.
Preflight request
를 걸러내기 위해선 HTTP Method에 OPTIONS
가 있는 것을 확인하여 해당 메소드가 있다면 그 요청을 자연스럽게 넘기는 과정을 추가하면 될 것이라 판단하였습니다.
@Component
@RequiredArgsConstructor
public class AuthenticationInterceptor implements HandlerInterceptor {
private final TokenManager tokenManager;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// preflight 요청 넘기기
if (request.getMethod().equals("OPTIONS")) {
return true;
}
// 1. Authorization Header 검증
String authorization = request.getHeader("Authorization");
AuthorizationHeaderUtils.validateAuthorization(authorization);
// 2. 토큰 검증
String accessToken = authorization.split(" ")[1];
tokenManager.validateToken(accessToken);
// 3. 토큰 타입
Claims tokenClaims = tokenManager.getTokenClaims(accessToken);
String tokenType = tokenClaims.getSubject();
if (!TokenType.isAccessToken(tokenType))
throw new AuthenticationException(ErrorCode.NOT_ACCESS_TOKEN_TYPE);
return true;
}
}
코드를 수정하고나니 요청이 정상적으로 처리됨을 확인할 수 있었습니다! 👏
처음엔 많이 당황했던 문제였지만, 프런트 팀원과의 수많은 고뇌(?) 끝에 발견 후 해결할 수 있었습니다.
저 혼자만의 프로젝트였다면 더 오래걸렸을지도 모릅니다... (오늘도 잘 맞는 팀원에 대한 소중함을 느끼게 됩니다...🥹)
당장은 급한 불을 끄듯 문제를 해결하였지만, CORS에 대한 깊은 학습이 필요하다고 느꼈습니다. (많은 분들이 직면하고 고생하시는 CORS...)
다음 포스팅은 CORS에 대한 학습 후에 상세히 기록물을 남겨두고자 합니다!
다음번에 만나요 🙋♂️