이번에는 큰 틀에서 auth 관련을 개선하면서 JWT 부분을 개선해보고자 한다.
각 클래스별로 의존성들을 확인해보고, 리뷰어가 이해하기 쉽고, 유지보수하기 좋은 형태로 개선하고자 노력해보자. (이번 기회에 레거시 코드도 읽어보고 ,, 좋다)
굵직한 부분들을 위주로 분석해보고 자세한 사항은 PR을 참고하여 변경사항을 보면 좋을 것 같다.
먼저 이전 코드(레거시)의 형태를 봐보자.. (부끄럽다)

이 클래스는 Spring Security에서 인증되지 않은 사용자가 보호된 리소스에 접근할 때 실행되는 인증 진입점 역할을 한다.
Spring Security의 AuthenticationEntryPoint 구현
JSON 형식의 에러 응답 처리
예외 발생 시 자동으로 실행
CustomException을 직접 응답 객체로 사용
예외 객체(CustomException)를 JSON 변환하여 클라이언트에 응답하지만, 예외 객체는 일반적으로 프로그램 내에서만 사용되는 것이 바람직하다.
API 응답을 담당하는 DTO (예: ErrorResponse) 없이, 예외 객체를 직접 JSON으로 변환하는 것은 설계적으로 부적절하다.
ObjectMapper를 통한 수동 JSON 변환
예외 처리를 CustomJwtAuthenticationEntryPoint 내부에서 처리

CustomJwtAuthenticationEntryPoint에서 직접 응답을 처리하지 않고, 예외를 던지는 방식으로 변경 (throw new JwtException(JwtErrorCode.INVALID_JWT_TOKEN)).@RestControllerAdvice와 @ExceptionHandler를 사용하여 전역 예외 처리를 담당하도록 개선.JwtException 클래스 도입 및 JwtErrorCode Enum 활용
JwtException으로 한 곳에서 통합 관리.JwtErrorCode Enum을 활용하여 에러 코드 및 메시지를 일관되게 정의.ObjectMapper 제거 및 ResponseEntity 활용
HttpServletResponse를 직접 조작하는 대신, Spring의 ResponseEntity를 사용하여 JSON 응답을 자동 변환.JwtException을 던지면 전역 예외 핸들러에서 이를 감지하고 자동으로 처리.AuthenticationException 발생 시 commence() 실행.JwtException(JwtErrorCode.INVALID_JWT_TOKEN) 예외 발생.GlobalExceptionHandler에서 JwtException을 감지하고 적절한 HTTP 응답을 반환.
이 클래스는 Spring Security에서 JWT 기반 인증을 수행하는 필터로,
클라이언트 요청에서 JWT 토큰을 추출하고 검증하여 인증을 처리하는 역할을 한다.
예외 처리가 적절하지 않음
try-catch 블록에서 예외 발생 시 로깅만 수행하고 예외를 적절히 처리하지 않음.JWT 검증 로직의 분리 부족
jwtTokenProvider.validateToken(token)을 직접 호출하여 검증 수행.getUserId(token)에서 jwtTokenProvider.getUserFromJwt(token)을 호출해 사용자 ID를 추출하는데, 검증과 사용자 ID 추출이 하나의 클래스에서 이루어짐.토큰 추출 로직이 복잡함
getAccessTokenFromRequest() → isContainsAccessToken() → getAuthorizationAccessToken() → getTokenFromBearerString() 형태로 복잡하게 구성되어 있음.val을 사용하여 가독성이 떨어질 수 있음.하드코딩된 상수 사용
"Bearer " 문자열을 ValueConfig.BEARER_HEADER에서 관리하지만, getTokenFromBearerString()에서 직접 문자열을 다룸.
try-catch 블록을 제거하고 Optional을 활용하여 예외 발생 시 코드가 자연스럽게 처리되도록 변경.JwtTokenVerifier 클래스를 사용하여 JWT 검증 및 사용자 ID 추출을 한 곳에서 처리.validateAndExtractUserId() 메서드를 통해 검증과 사용자 ID 추출을 동시에 수행.extractToken(request) 메서드를 추가하여 토큰을 단순하게 추출.Optional<String>을 사용하여 null 처리를 자연스럽게 해결.map(token -> token.replaceFirst("Bearer ", "").trim())을 활용하여 불필요한 메서드 체이닝 제거.authenticateUser(Long userId) 메서드에서 UserDetailsFactory를 사용하여 사용자 객체 생성.UserAuthentication.authenticated(userDetails)를 활용하여 명확한 인증 객체 생성.

JWT 키 생성 로직이 JwtTokenProvider에 직접 포함됨
getSigningKey() 메서드에서 키를 생성하는데, 이는 JWT 검증 및 생성 로직과 분리되지 않아 단일 책임 원칙(SRP)에 위배됨.JWT 발급, 검증, 클레임 생성이 한 클래스에서 이루어짐
generateToken(), validateToken(), getUserFromJwt()가 같은 클래스(JwtTokenProvider)에 존재하여 관심사가 분리되지 않음.예외 처리가 일관되지 않음
validateToken()에서 예외를 log.error(exception.getMessage());로 기록 후 단순히 JwtValidationType을 반환.ExceptionHandler)가 존재하지 않아 일관된 예외 처리 및 응답이 어렵다.하드코딩된 값이 포함됨
claims.put("userId", authentication.getPrincipal()); 등의 값이 하드코딩되어 있음.JwtKeyProvider 도입)
JwtKeyProvider 클래스를 추가하여 JWT 키 생성 역할을 별도로 분리.JwtTokenProvider에서 JWT 서명 키를 직접 생성하는 것이 아니라, JwtKeyProvider.getSigningKey()를 통해 키를 가져오도록 변경.
JwtSigner: JWT 서명 및 발급 담당.
JwtClaimsGenerator: 클레임 생성 담당.
JwtTokenIssuer: 토큰 발급을 담당하는 상위 모듈로 변경.
JwtTokenManager: 실제 서비스에서 JWT 토큰을 발급 및 관리하는 역할 수행.
이점:
JwtValidationType을 반환하는 방식 대신 예외를 던지는 방식으로 변경.JwtException 및 GlobalExceptionHandler를 활용하여 일관된 예외 처리를 보장.INVALID_JWT_TOKEN, EXPIRED_JWT_TOKEN 등)를 JwtErrorCode Enum으로 정의하여 예외 메시지를 일관되게 유지.