2025. 12. 17. 09:11ㆍSpring Security
이번 챕터에서는 JWT 기반 인증 시스템에서 UsernamePasswordAuthenticationFilter와 커스텀 JwtAuthenticationFilter가 공존하고 상호작용하는 복잡한 필터 체인 설계에 대해 설명하겠습니다.
🚀 JWT 환경에서의 필터 체인 상호작용 심층 분석
JWT (JSON Web Token) 기반 인증 시스템에서 두 필터가 공존하는 이유는 처리해야 하는 요청의 유형과 목적이 근본적으로 다르기 때문입니다.
1. 필터 공존의 핵심 원칙: 요청 분리 (Request Segregation)
대부분의 현대 API는 두 가지 유형의 요청을 처리합니다.
| 요청 유형 | 목적 | 필터 처리 |
|---|---|---|
| Authentication Request | ID/PW를 제출하여 최초 토큰을 획득하는 과정 (/login POST) |
UsernamePasswordAuthenticationFilter (또는 커스텀 구현체) |
| Resource Request | 보호된 리소스에 접근하기 위해 이미 획득한 토큰을 제출하는 과정 (/api/** GET/POST) |
JwtAuthenticationFilter (커스텀 필터) |
UsernamePasswordAuthenticationFilter를 제거하지 않는 이유는 유형 1의 요청을 처리할 메커니즘이 필요하기 때문입니다.
2. JwtAuthenticationFilter를 앞에 두는 이유 (우선순위의 중요성)
개발자가 커스텀 JwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter보다 앞에 배치하는 것은 효율성과 로직의 명확성을 위한 표준 관례입니다.
A. 토큰 기반 요청의 빠른 처리 (대부분의 요청)
JwtAuthenticationFilter실행: 대부분의 API 요청은 이미Authorization: Bearer <token>헤더를 포함하고 있습니다.- 토큰 검증 및 인증: 필터는 이 토큰을 추출하고 검증한 후, 유효하면
SecurityContext에Authentication객체를 설정합니다. - 체인 중단/계속: 인증이 성공적으로 완료되면,
JwtAuthenticationFilter는 다음 필터로 진행하지 않고FilterChain.doFilter()호출을 중단하고 요청을 컨트롤러로 바로 넘깁니다. (또는 명시적으로 다음 필터 체인의 진행을 막는 로직을 구현합니다.) \toUsernamePasswordAuthenticationFilter는 실행되지 않습니다.
B. 로그인 요청으로 체인이 진행되는 경우 (예외적인 경우)
JwtAuthenticationFilter실행: 요청이/login(POST)이고, 이 요청에는 토큰이 포함되어 있지 않거나 있어도 무시됩니다. 필터는 인증을 설정하지 않고 다음 필터로 진행시킵니다.UsernamePasswordAuthenticationFilter실행: 이 필터는 요청이 자신의 매칭 경로(/login)이고 HTTP 메서드(POST)에 맞는지 확인합니다. 조건이 맞으면 ID/PW를 추출하여 인증을 시도합니다.- 인증 성공/실패: 성공하면
Authentication객체가 반환되고, 이 객체를 사용하여 JWT 토큰을 생성하는 로직이 실행됩니다 (보통AuthenticationSuccessHandler또는 커스텀AuthenticationFilter의 역할).
요약하자면, JwtAuthenticationFilter는 토큰 기반 요청을 처리하여 필터 체인을 조기에 우회(Bypass)시키는 역할을 하고, UsernamePasswordAuthenticationFilter는 조기 우회에 실패한 요청 중 최초 로그인 요청을 전담하는 구조로 분리하여 효율성을 극대화하는 것입니다.
3. UsernamePasswordAuthenticationFilter의 역할 변경 (Deactivation)
일부 설계에서는 토큰 발급 로직을 위해 UsernamePasswordAuthenticationFilter를 사용하지 않고, 아예 별도의 커스텀 필터나 일반 Spring MVC 컨트롤러를 만들어 ID/PW 로그인을 처리하기도 합니다.
A. 컨트롤러 기반 토큰 발급
- 개발자는
/loginPOST 요청을 처리하는 일반@RestController를 만듭니다. - 컨트롤러 내에서
AuthenticationManager를 직접 주입받아 ID/PW로 인증을 시도하고, 성공하면 직접 JWT 토큰을 생성하여 응답합니다. - 이 경우,
UsernamePasswordAuthenticationFilter는 필요가 없으므로 필터 체인에서 명시적으로 비활성화(Disable)하거나 제거할 수 있습니다.
// HttpSecurity 설정에서 폼 로그인을 비활성화하여 해당 필터를 제거합니다.
http.formLogin(AbstractHttpConfigurer::disable);
결론적으로,
- 공존하는 경우:
UsernamePasswordAuthenticationFilter는 로그인 요청 처리라는 명확한 목적을 가지고 체인에 남습니다. - 제거하는 경우: 개발자가 로그인 요청 처리 로직을 별도의 컨트롤러로 완전히 분리했을 때
UsernamePasswordAuthenticationFilter를 제거합니다.
이러한 유연한 설계 덕분에 Spring Security는 다양한 인증 방식(세션, JWT, OAuth2)에 대응할 수 있습니다.
'Spring Security' 카테고리의 다른 글
| JWT 필터 삽입 위치 및 UsernamePasswordAuthenticationFilter의 존속 여부 설명 (0) | 2025.12.17 |
|---|---|
| HttpSecurity (0) | 2025.12.16 |
| SecurityFilterChain (0) | 2025.12.16 |
| @EnableWebSecurity 어노테이션 (0) | 2025.12.16 |
| ch15 Implementing an OAuth 2 resource server (0) | 2024.12.17 |