안녕하세요. 토이 프로젝트를 진행하다가 jwtFilter에서 예외가 발생했을 때, ControllerAdvice로 처리를 했습니다. 그랬더니 500이 떨어졌는데요. 서버에서의 로그를 확인해 보니 jwt의 사용 기한이 경과되었다와 같은 jwt exception이 그대로 떨어졌습니다. 저는, jwt token이 유효하지 않다면, fe단에서 왜 유효하지 않은지 알 수 있게 custom한 메세지와 응답 코드를 뿌려주려고 했습니다. 어떤 식으로 적용을 했는지 간단하게 소개해 보도록 하겠습니다.

 


 공식 문서를 보면 Spring Security에서 Filter에 대한 개략적인 그림이 있어요. 이 그림과 서버에 나타난 로그를 보고 어떻게 코드를 바꿔야 할 지 고민해 보겠습니다.

 

 

 먼저 GET /borrow는 인증이 되어야 호출할 수 있는 메서드입니다. 로그인을 성공하면 access_token만 뿌려주게 되는데요. 여기서 맨 뒤에 있는 문자만 하나 바꿔서 보내보도록 하겠습니다.

 

 

 -H 옵션이 붙었으니, jwt_access_token은 헤더로 보내나 보네요. 응답을 보겠습니다.

 

 

 Internal Server Error가 뜨는데요. JwtToken을 처리하는 과정에서 걸렸을 겁니다. 그리고, JwtToken을 처리하는 로직은 아래와 같이 수정을 한 상태입니다.

 

 

 이전 코드는 getTokenBody 부분에서 return 문만 있었습니다. 이것을 리턴하는 과정에서 예외가 발생하면 공통적으로 같은 예외인 jwtTokenNotAvailable 예외를 던져버렸습니다.

 

 

 getUserToJwtToken 부분도 딱히 TokenBody의 예외를 잡지는 않습니다. 그러니 호출한 쪽에 던져집니다.

 

 

  jwtFilter의 doFilterInternal 부분에서도 getUserToJwtToken의 예외를 처리하지는 않습니다. 그러니, 이전 필터로 계속 예외가 던져질 겁니다.

 

 SecurityConfig 클래스의 코드 일부를 보면, 테스트 용으로 jwtFilter 전에 jwtExceptionFilter를 걸어 놓았는데요. 어떻게 trace가 걸리는지 보겠습니다.

 

 

 보니까, JwtFilter의 doFilterInternal이 trace가 걸렸는데, 밑에 보시면 JwtExceptionFilter의 doFilterInternal에도 trace가 걸려 있어요. 그런데 맨 위에를 보면 JwtUtil의 getTokenBody가 trace가 또 걸려있는데요. 위에 있을수록 호출 depth가 깊다는 것을 눈치챌 수 있어요. 이걸 잘 이용해서 내부 소스를 본 적도 상당히 많았습니다. 그러니 서버에 로그를 남길 때 어떤 식으로 남겨야 하는지 고민을 해 볼 필요는 있습니다.

 

 이를 토대로 어떤 식으로 호출이 되었고, 어떤 식으로 예외가 계속 던져져서 결국에는 500이 떨어졌는지 보겠습니다. 공식 문서를 보시면, FilterChain 그림이 있어요. 이게 무엇인진 모르겠지만 SecurityConfig 클래스에서 필터를 요래 설정해 버렸습니다.

 

 

 jwtFilter 전에 jwtExceptionFilter를 설정했고, jwtFilter는 password..Filter 전에 추가하는 것으로 수정했습니다. 예외 trace에 나타난 대로 호출 구조만 개략적으로 그려 보면 아래와 같을 겁니다.

 

 

 jwtExceptionFilter가 doFilter를 호출하면 일련의 과정을 거쳐서, jwtFilter의 doFilterInternal를 호출합니다. 그리고 그 안에서는 jwtUtil의 getUserToJwtToken를 호출하고 getUserToJwtToken은 getTokenBody을 호출하게 됩니다. 그런데 getTokenBody에서 예외가 발생하였어요.

 

 

 이 상황을 그림으로 나타내면 위와 같아요. 그런데, getTokenBody에서 예외를 throw만 했고, getUserToJwtToken도 catch를 하지 않습니다. jwtFilter 단에서도 catch를 받지 않으므로, jwtExceptionFilter로 넘어갑니다.

 

 

 그런데 jwtExceptionFilter가 잡지 않습니다. 그러면 상위 필터로 넘어가게 될 겁니다.

 

 


 그러면 어떻게 해야 할까요? jwtExceptionFilter를 jwtFilter 이전에 추가하였으므로, jwtExceptionFilter에서 예외를 catch 해 주시면 됩니다.

 

 

 34번째 줄부터 42번째 줄은 jwtTokenNotAvailable 예외를 catch 했을 때 처리하는 로직입니다. 이 부분은 구글링을 해 보시면 잘 구현하실 수 있습니다. 저는 이 답변을 보고 구현했습니다.

 

 

 아까와 같이 잘못된 token을 보내보았더니, 인증 Token signature가 올바르지 않다는 custom message와 401이 떨어집니다. 이 부분을 제 토이 프로젝트에 반영한 것은 링크에 있습니다. 정리하면, Filter A에서 발생하는 예외를 custom message로 떨구고 싶다면, Filter A 전에 Filter ExceptionA를 추가하고, ExceptionA에서 Filter A에서 발생하는 예외를 catch 해 주시면 됩니다.