JWT 필터 에러핸들링

3206 단어 삽질삽질

우리 팀 프로젝트에서

GlobalErrorHandel 이라는 파일을 만들어 서버 전역에서 일어나고 있는

에러들을 모두 모아 컨트롤 하려고 하고 있었다.

하지만, 이 포위망을 뚫고 나가는 에러... JWT에러를 잡을 수 없었다.

JWT 토큰 만료시 커스텀한 에러 메세지를 만들려고 했지만 생각대로 되지 않았고,

이때 스프링 구조를 공부해야겠다는 생각이 들었다.

JWT 토큰 검증 과정은 Filter 부분에서 이루어 지고

@RestControllerAdvice는 HandlerIntercepter 쪽이기 때문에
애초에 만날 일이 없었다.

그렇기에 애초에 Filter 단에서 백날천날 에러를 던져봐야

받을 수 없는 구조였던 것이다...!!!

그래서 JwtAuthenticationFilter 앞단에 토큰을 검증한 뒤
해당 에러에 대해 핸들링을 해주는

JwtExceptionFilter를 앞단에 만들어 주었다!

... TokenValidator 수정 ...

...

try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
            System.out.println("토큰 검증 성공");
            return !claims.getBody().getExpiration().before(new Date());
        } catch (ExpiredJwtException e) {
            System.out.println(e.getClass());
            log.info("만료된 JWT 토큰입니다.");
            throw new JwtException("Expired");
        } catch (MalformedJwtException e) {
            System.out.println(e.getClass());
            log.info("잘못된 JWT 토큰입니다.");
            throw new JwtException("잘못된 JWT 서명입니다.");
        } catch (UnsupportedJwtException e) {
            System.out.println(e.getClass());
            log.info("지원하지 않는 JWT 토큰입니다.");
            throw new JwtException("지원하지 않는 JWT 토큰입니다.");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getClass());
            log.info("잘못된 JWT 토큰입니다.");
            throw new JwtException("JWT 토큰이 잘못되었습니다.");
...

... JwtExceptionFilter ...

@Component
public class JwtExceptionFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
        try {  // 앞단 필터에서 에러가 있을 시 이 필터로 넘어온다.
            chain.doFilter(req, res); // go to 'JwtAuthenticationFilter'
        } catch (JwtException ex) {
            setErrorResponse(HttpStatus.UNAUTHORIZED, res, ex);
        }
    }

    public void setErrorResponse(HttpStatus status, HttpServletResponse response, Throwable ex) throws IOException {
        response.setStatus(status.value());
        response.setContentType("application/json; charset=UTF-8");

        JSONObject responseJson = new JSONObject();
        responseJson.put("HttpStatus", HttpStatus.UNAUTHORIZED);
        responseJson.put("message", ex.getMessage());
        responseJson.put("status", false);
        responseJson.put("statusCode", 401);
        responseJson.put("code", "401");
        response.getWriter().print(responseJson);
    }
}

이렇게 하니 필터 단에서 에러를 핸들링 한 뒤

그대로 내보내 줄 수 있는 설계를 할 수 있었다!

참고 문서

https://velog.io/@hellonayeon/spring-boot-jwt-expire-exception

좋은 웹페이지 즐겨찾기