- 커스텀 필터를 직접 구현하는 방법
- GenericFilterBean을 확장하여 필터를 구현하는 방법
- OncePerRequestFilter를 활용하여 요청당 한번만 실행되는 필터 작성하기
- 필터 내부에서 요청 / 응답 객체를 다루고 원하는 로직을 삽입하는 방법
- 실무에서 자주 사용되는 커스텀 필터 패턴 예시
커스텀 필터 구현 방법
1. GenericFilterBean 확장
Spring Security에서 필터를 구현할 때 가장 기본적으로 사용할 수 있는 클래스
javax.servlet.Filter 를 구현한 추상 클래스이며, 스프링 빈으로 등록 가능하도록 지원한다
CustomGenericFilter 클래스, GenericFilterBean을 상속함
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.springframework.web.filter.GenericFilterBean;
import java.io.IOException;
public class CustomGenericFilter extends GenericFilterBean { // GenericFilterBean을 extends 한 다음
// doFilter 메서드만 구현하면 됨
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
// 요청 전 처리 로직
System.out.println("[CustomGenericFilter] 요청 처리 전 실행하기");
// 필터 체인 진행
filterChain.doFilter(servletRequest, servletResponse);
// 응답 후 처리 로직
System.out.println("[CustomGenericFilter] 응답 처리 후 실행하기");
}
}
요청이 들어올때와 응답이 나갈 때 모두 원하는 로직을 삽입할 수 있다
(1) 실무 활용 예(GenericFilterBean)
사용자 세션 만료 처리 : 로그인은 되어 있지만, 세션 만료 시간이 지난 경우 자동으로 로그아웃 처리됨
IP 화이트리스트 : 특정 API는 내부망 IP에서만 접근하도록 제한하게끔 함
// 요청 전 처리 로직
System.out.println("[CustomGenericFilter] 요청 처리 전 실행하기");
// 전처리
String clientIp = servletRequest.getRemoteAddr();
List<String> whiteList = List.of("127.0.0.1", "192.168.0.10");
if(!whiteList.contains(clientIp)) {
servletResponse.setContentType("text/plain;charset=utf-8");
servletResponse.getWriter().write("허용되지 않은 IP입니다.");
return; // 꼭 해줘야함, 필터 체인 중단
}
GenericFilterBean은 요청과 응답을 모두 다루며, 전후 처리 제어가 필요한 경우 주로 사용된다
2. OncePerRequestFilter 활용하기
Security에서 커스텀 필터를 구현할 때 가장 많이 사용하는 클래스임
하나의 요청당 반드시 한번만 실행되도록 보장한다
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
public class CustomOncePerRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
/**
* 요청 전 처리
* 클라이언트의 IP를 가져온다
* OS 레벨의 TCP 이후 tomcat을 통해 IP를 가져옴
*/
String clientIp = request.getRemoteAddr();
System.out.println("[CustomOncePerRequestFilter] 클라이언트 IP : " + clientIp);
// 필터 체인 진행
filterChain.doFilter(request, response);
// 응답 후 처리
System.out.println("[CustomOncePerRequestFilter] 응답 완료");
}
}
주로 인증 / 인가 검증, 로깅, 헤더 검증 등의 작업에서 활용된다
(1) 실무 활용 예시(OncePerRequestFilter)
JWT 토큰 검증 : 요청 헤더에 포함된 토큰을 파싱하고 유효성을 검사한 뒤, 인증 객체를 SecurityContext에 저장함
String clientIp = request.getRemoteAddr();
System.out.println("[CustomOncePerRequestFilter] 클라이언트 IP : " + clientIp);
String token = request.getHeader("Authorization");
if(token != null && token.startsWith("Bearer")) {
// 토큰 파싱 및 검증 로직 구현
// 검증에 성공하면 Authentication 객체 생성 후 SecurityContext에 저장하는 로직
}
요청 추적 ID 로깅 : MSA 환경에서 모든 요청에 공통 Trace ID를 심어서 로그를 추적함
// 전처리 일부
String token = request.getHeader("Authorization");
if(token != null && token.startsWith("Bearer")) {
// 토큰 파싱 및 검증 로직 구현
// 검증에 성공하면 Authentication 객체 생성 후 SecurityContext에 저장하는 로직
}
// 이 부분
String traceId = UUID.randomUUID().toString();
response.getHeader("X-Trace-Id" + traceId);
System.out.println("[Trace] 요청 추적 ID : " + traceId);
OncePerRequestFilter는 요청마다 반드시 한번 실행되어야 하는 보안 / 로그 / 추적 로직에 적합하다
3. 필터 로직 구현
커스텀 필터 안에서는 요청과 응답 객체를 자유롭게 다룰 수 있다
(1) 요청(Request) 활용 예시
String token = request.getHeader("Authorization");
if(token == null && token.startsWith("Bearer ")) {
// 토큰 파싱 및 검증 로직 구현
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return; // 인증에 실패하면 필터체인이 중단됨
// 검증에 성공하면 Authentication 객체 생성 후 SecurityContext에 저장하는 로직
}
(2) 응답 활용 예시
String traceId = UUID.randomUUID().toString();
response.addHeader("X-Trace-Id", traceId);
// 여기
response.addHeader("X-Custom-Header", "CustomValue");
System.out.println("[Trace] 요청 추적 ID : " + traceId);
이런식으로 요청 헤더를 검사하거나 응답 헤더를 추가하여 보안을 강화할 수 있다
팁
- GenericFilterBean 은 단순히 필터 구조를 직접 제어해야할 때 유용하다
- OncePerRequestFilter 대부분의 경우 추천되며, 중복 실행 방지가 필요한 로직에 적합하다
- 필터 내부에서 무거운 연산을 수행하면 전체 요청 처리 성능이 저하될 수 있다. 주의해야함
- 예외가 발생하면 적절히 처리해야함. "전체" 애플리케이션이 에러 응답을 반환할 수 있다
'Spring Boot > Security' 카테고리의 다른 글
| 커스텀 필터 구현 : 구현해보기 (0) | 2026.05.01 |
|---|---|
| 커스텀 필터 구현 : 필터체인에 커스텀 필터 추가하기 (0) | 2026.05.01 |
| 커스텀 필터 구현 : 필요성 (0) | 2026.04.29 |
| * 인가 아키텍처 : 핵심 컴포넌트 * (0) | 2026.04.29 |
| 인가 아키텍처 : 인가 프로세스 (0) | 2026.04.28 |