che01 님의 블로그
Spring Boot JWT 인증 본문
JWT 필터 트러블슈팅
문제 상황 개요
JWT 토큰을 이용한 인증 필터 구현 중 유저 ID 타입 불일치와 필터 중복 호출 문제가 발생했다.
문제 1: 유저 ID 타입 불일치로 인한 인증 실패
증상
- JWT 토큰에서 유저 ID를 추출했지만 데이터베이스에서 유저를 찾지 못함
- "해당 유저가 없습니다" 예외가 지속적으로 발생
- SecurityContext에 유저 정보가 저장되지 않음
원인 분석
데이터베이스의 User 엔티티 ID는 Long 타입으로 설계되어 있지만, JWT 토큰에서 추출한 사용자 ID는 String 타입이었다. JPA Repository의 findById() 메서드가 타입 불일치로 인해 올바른 매칭을 수행하지 못했다.
문제 코드
// 기존 코드 - 타입 불일치 발생
String userId = jwtUtil.extractuserId(jwt);
User user = userRepository.findById(userId); // String을 Long ID로 조회 시도
해결 코드
// 수정된 코드 - 타입 변환 적용
String subject = jwtUtil.extractuserId(jwt);
Long userId = Long.parseLong(subject); // String을 Long으로 변환
User user = userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("해당 유저가 없습니다."));
문제 2: 필터 중복 호출 현상
증상
첫 번째 문제를 디버깅하는 과정에서 하나의 HTTP 요청에 대해 JWT 인증 필터가 여러 번 실행되는 것을 발견했다. 동일한 토큰 검증 로직이 중복으로 수행되어 성능 저하가 발생했다.
원인 분석
기본 Filter 인터페이스를 구현했을 때 Spring의 필터 체인에서 중복 호출이 발생할 수 있다. 포워딩, 리다이렉트, 에러 처리 시 필터가 재실행되는 경우가 있다.
해결방법
OncePerRequestFilter를 상속받아 해결했다.
// 기존: 일반 Filter 구현
public class JwtAuthenticationFilter implements Filter {
// 중복 호출 가능성 존재
}
// 수정: OncePerRequestFilter 상속
public class JwtAuthenticationFilter extends OncePerRequestFilter {
// 요청당 한 번만 실행됨이 보장
}
OncePerRequestFilter를 사용하면 동일한 HTTP 요청에 대해 필터가 한 번만 실행되어 성능이 최적화되고 예측 가능한 동작을 보장한다.
검증 및 테스트
타입 변환 문제 해결 확인
유저 ID 타입 변환 로직에 대한 단위 테스트를 작성하여 실제 토큰으로 유저 조회가 성공하는지 확인했다.
필터 중복 호출 방지 확인
애플리케이션 로그를 통해 필터 실행 횟수를 모니터링하고, 성능 테스트를 통해 응답 시간이 개선되었는지 확인했다.
주요 학습 포인트
- JWT 페이로드와 데이터베이스 스키마 간 타입 일치성이 중요하다
- Spring Boot에서는 OncePerRequestFilter 사용을 권장한다
- 불필요한 중복 실행을 방지하여 성능을 최적화할 수 있다
이 문제를 해결함으로써 안정적이고 효율적인 JWT 인증 시스템을 구축할 수 있었다.