JwtAuthenticationFilter는 JWT 토큰으로 인증하고 SecurityContextHolder에 추가하는 필터를 설정하는 클래스
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
private final JwtTokenProvider jwtTokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider){
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(servletRequest);
LOGGER.info("[doFilterInternal] token 값 추출 완료, token: {}", token);
LOGGER.info("[doFilterInternal] token 값 유효성 체크 시작");
if(token != null && jwtTokenProvider.validateToken(token)){
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
LOGGER.info("[doFilterInternal] token 값 유효성 체크 완료");
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
스프링 부트에서는 필터를 여러 방법으로 구현하는데, 가장 편한 구현 방법은 필터를 상속받아 사용하는 것
-> 대표 적인 상속 객체는 GenericFilterBean
& OncePerRequestFilter
GenericFilterBean
은 기존 필터에서 가져올 수 없는 스프링의 설정 정보를 가져올 수 있게 확장된 추상 클래스
다만 서블릿은 사용자의 요청을 받으면 서블릿을 생성해서 메모리에 저장해두고 동일한 클라이언트의 요청을 받으면 재활용하는 구조여서 이를 상속받으면 RequestDispatcher에 의해 다른 서블릿으로 디스패치 되면서 필터가 두번 실행될 수 있음
-> 이를 해결하기 위해 등장한 것이 OncePerRequestFilter
이며 이 또한 GenericFilterBean을 상속받고 있음
doFilter()
는 서블릿을 실행하는 메서드인데, 이를 기존으로 앞에 작성한 코드는 서블릿 실행되기 전에 실행되고, 뒤에 작성한 코드는 서블릿 실행된 후 실행
메서드 로직을 보면 JwtTokenProvider
를 통해 servletRequest에서 토큰을 추출하고, 토큰에 대한 유효성 검사
-> 토큰이 유효하다면 Authentication 객체를 생성해서 SecurityContextHolder에 추가
GenericFilterBean을 상속받아 구현한 경우
public class JwtAuthenticationFilter extends GenericFilterBean{
private final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
private final JwtTokenProvider jwtTokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider){
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken((HttpServletRequest) servletRequest);
LOGGER.info("[doFilterInternal] token 값 추출 완료, token: {}", token);
LOGGER.info("[doFilterInternal] token 값 유효성 체크 시작");
if(token != null && jwtTokenProvider.validateToken(token)){
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
LOGGER.info("[doFilterInternal] token 값 유효성 체크 완료");
}
filterChain.doFilter(servletRequest, servletResponse);
}
}