Spring Security에서 OncePerRequestFilter를 확장하여 모든 요청마다 JWT를 검사하고 유효하면 인증 정보를 SecurityContext에 저장하는 역할
Spring Security에서 제공하는 필터로, 한 번의 요청에 대해 단 한 번만 실행되는 필터
Spring Security에서 요청이 들어올 때, 여러 개의 필터가 체인 형태로 실행됩니다.
하지만 일부 필터는 같은 요청에 대해 여러 번 실행되면 안 되는 경우가 있음. (ex. JWT 인증 필터, 로깅 필터, CORS 필터 등)
➡ 이를 방지하기 위해 OncePerRequestFilter를 상속받은 필터는 한 번의 요청당 딱 한 번만 실행됨.
doFilterInternal()을 구현해야 하며, 반드시 filterChain.doFilter(request, response); 호출 필요
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// "/api/auth/kakao 경로로의 요청은 필터를 실행하지 않도록 걸러낸다.
if (!request.getRequestURI().equals("/api/auth/kakao") && !request.getRequestURI().equals("/api/auth/newToken")) {
String jwt = resolveToken(request);
log.info("jwt token = {}", jwt);
try {
if (jwtProvider.validateToken(jwt)) {
Authentication authentication = jwtProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (AuthErrorException e) {
throw new RuntimeException(e);
}
}
filterChain.doFilter(request, response);
}
1️⃣ doFilterInternal()의 역할
: SecurityContext에 Access Token으로부터 뽑아온 인증 정보를 저장하는 메서드
doFilterInternal() 내부에서 수행하는 작업
resolveToken() : HTTP 쿠키 or 헤더에서 JWT 가져온다.jwtProvider.validateToken(jwt) : 요청에 JWT가 있으면 유효성을 검사하고 사용자 이름을 구문 분석한다.Authentication authentication = jwtProvider.getAuthentication(jwt); : 사용자 이름에서 UserDetails를 가져와 인증 개체를 만든다.SecurityContextHolder.getContext().setAuthentication(authentication); : setAuthentication(authentication) 메서드를 사용하여 SecurityContext에서 현재 UserDetails를 설정한다.filterChain.doFilter(request, response); : 현재 필터 실행 후 다음 필터(ex. 인증, 인가 필터)로 요청을 전달하는 역할 (마지막 필터까지 실행된 후, 컨트롤러로 요청이 전달됨)📌 UserDetails란?
🔹 Spring Security에서 사용자 정보를 담는 인터페이스 (Spring Security가 자동으로 관리)
🔹 jwtProvider.getAuthentication(jwt)가 반환하는 Authentication 객체 안에는 UserDetails 구현체가 들어 있습니다.
📌 왜 UserDetails가 필요할까?
Spring Security는 UserDetails를 기반으로 사용자 인증을 처리함.
JWT에서 사용자 정보를 추출한 후, UserDetails로 변환하여 인증 객체를 만들고 SecurityContext에 저장함.
private String resolveToken(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (StringUtils.hasText(token) && token.startsWith(BEARER_PREFIX)) {
return token.substring(7);
}
return null;
}
2️⃣ resolveToken()의 역할
: 요청의 Authorization 헤더에서 JWT를 추출
tokeb.substring(7) : 문자열의 7번째 인덱스부터 끝까지 가져옴
📌 Authorization 헤더 형식
Authorization: Bearer <토큰 값>
"Bearer "는 토큰을 사용할 때 붙이는 표준 prefix
"Bearer " 접두사가 있으면 제거하고 순수한 토큰 값만 반환합니다.