JwtAuthenticationFilter

한지혜·2025년 3월 3일

JWT

목록 보기
1/3
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserDetailsService userDetailsService;

    public JwtAuthenticationFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
        this.jwtUtil = jwtUtil;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");

        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);

            if (jwtUtil.validateToken(token)) {
                String username = jwtUtil.getUsernameFromToken(token);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);

                SecurityContextHolder.getContext().setAuthentication(
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));
            }
        }

        filterChain.doFilter(request, response);
    }
}

코드 설명

  1. @Component
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
  • 이 필터가 Spring Bean으로 등록되도록 설정함.
  • Spring Security 필터 체인에 자동으로 포함됨.

OncePerRequestFilter란?

  • 요청당 한 번만 실행되는 필터
  • 클라이언트의 모든 요청에서 JWT를 검사할 때 적합함.

  1. JwtUtil, UserDetailsService 주입
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;

public JwtAuthenticationFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
    this.jwtUtil = jwtUtil;
    this.userDetailsService = userDetailsService;
}
  • JwtUtil: JWT 생성/검증 도구 (토큰을 검증하고 사용자 정보 추출)
  • UserDetailsService: DB에서 사용자 정보 로드 (Spring Security에서 제공하는 인터페이스

UserDetailsService는 loadUserByUsername(username)을 통해 DB에서 사용자 정보 (UserDetails 객체)를 가져오는 역할을 함.


  1. doFilterInternal() - 필터 실행 로직
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
  • 모든 HTTP 요청을 가로채서 JWT를 검사하는 핵심 메서드
  • HttpServletRequest → 클라이언트 요청 정보
  • HttpServletResponse → 서버 응답 정보
  • FilterChain → 다음 필터로 요청을 넘기는 역할

  1. Authorization 헤더에서 JWT 추출
String token = request.getHeader("Authorization");
  • 요청 헤더에서 Authorization 값을 가져옴.
  • JWT는 Authorization 헤더의 Bearer {토큰값} 형태로 전달됨.

  1. 토큰이 Bearer 로 시작하는지 확인 후 앞 7글자("Bearer ") 제거
if (token != null && token.startsWith("Bearer ")) {
    token = token.substring(7);
  • 토큰 값이 null이 아니고, Bearer 로 시작하면 실제 JWT 부분만 추출

ex) Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
"Bearer " 제거 후 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." 만 사용.


  1. JWT 검증
    if (jwtUtil.validateToken(token)) {
* jwtUtil.validateToken(token) → 토큰이 유효한지 검증
* validateToken()에서 서명이 올바르고 만료되지 않았는지 체크


---


7. 토큰에서 사용자 정보 추출
```java
String username = jwtUtil.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
  • jwtUtil.getUsernameFromToken(token) → JWT에서 username(subject) 가져옴.
  • userDetailsService.loadUserByUsername(username) → DB에서 해당 사용자 정보를 가져옴.

UserDetailsService가 하는 역할?
username을 기반으로 DB에서 사용자 정보를 가져와 UserDetails 객체를 생성함.
UserDetails 객체에는 사용자의 권한 정보 (Roles), 비밀번호 등이 포함됨.


  1. SecurityContext에 인증 정보 저장
SecurityContextHolder.getContext().setAuthentication(
    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));
  • Spring Security의 SecurityContext에 인증 정보를 저장
  • UsernamePasswordAuthenticationToken 객체를 생성해서 로그인된 상태로 만듦
    • userDetails: 사용자 정보
    • null: 비밀번호 (JWT는 비밀번호를 사용하지 않음)
    • userDetails.getAuthorities(): 사용자 권한 정보 (ROLE_USER, ROLE_ADMIN 등)

이 과정이 중요한 이유
SecurityContext에 인증 정보를 저장해야 Spring Security가 "이 요청은 인증된 사용자 요청이다"라고 인식함.
즉, 이 필터를 통과한 후에는 인증이 필요한 API도 접근 가능하게 됨.


  1. 다음 필터로 요청 전달
filterChain.doFilter(request, response);
  • 모든 필터를 거친 후, 최종적으로 컨트롤러(@RestController)로 요청이 전달됨.

전체 흐름 정리

  1. 요청을 가로챔 (doFilterInternal)
  2. Authorization 헤더에서 JWT 추출
  3. JWT 검증 (validateToken())
  4. JWT에서 사용자 정보 (username) 추출
  5. DB에서 사용자 정보 (UserDetails) 가져옴
  6. SecurityContext에 인증 정보 저장
  7. 다음 필터로 요청 전달 (filterChain.doFilter())

이 코드가 하는 일

  • 매 요청에서 JWT를 검사하고, 유효하면 Spring Security 인증 객체를 설정함
  • SecurityContextHolder에 사용자 정보를 저장해서 로그인된 상태로 API 접근 가능하게 만듦
  • 이 필터가 없으면, JWT가 있어도 인증되지 않음 (Spring Security가 JWT를 자동으로 처리해주지 않기 때문)
profile
공부

0개의 댓글