[JWT] LoginFilter 구현

nasohi·2026년 4월 9일

JWT

목록 보기
2/5

Login Filter

Spring Security의 기본 로그인 필터를 커스터마이징한 필터로,
로그인 요청을 가로채 인증을 수행하는 역할을 한다.

Spring Security는 기본적으로 UsernamePasswordAuthenticationFilter를 사용하여 로그인을 처리한다.
하지만 JWT 기반 인증을 적용하려면 로그인 성공 시 JWT를 발급해야하기 때문에 기본 필터를 그대로 사용할 수 없다.

따라서 기본 로그인 필터를 상속받아 LoginFilter를 직접 구현해야한다.

public class LoginFilter extends UsernamePasswordAuthenticationFilter

죽, 기존 로그인 필터를 확장하여 커스터마이징한 것이다.

  • Spring Security에는 원래 폼 로그인을 처리하는 필터가 내장되어있다. 이걸 상속받아서 직접 만든 방식으로 처리하도록 한다.
  • 사용자가 보낸 ID/PW가 맞는지 검사하고, 맞다면 JWT를 발급해주는 것이 목적이다.

왜 LoginFilter가 필요한가

기본 로그인 흐름은 다음과 같다.

로그인 요청 → 인증 → 세션 저장

하지만 JWT 방식에서는

로그인 요청 → 인증 → JWT 발급 → 클라이언트가 토큰 보관

위와 같이 동작해야한다.
따라서 로그인 성공시 JWT를 발급할 수 있는 지점이 필요하며, 그 역할을 LoginFilter가 수행해야한다.

    @Override // 로그인 시도할 때 실행되는 메서드
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)  throws AuthenticationException {

        //아이디, 비번 꺼내고 (obtain는 내부적으로 request.getParameter(""))
        String username = obtainUsername(request);
        String password = obtainPassword(request);

        // 토큰 생성 : 인증 요청 객체 (아직 인증 안됨)
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password,null);

        // 인증 시도 (service 호출 -> DB 조회 -> 비번 비교 -> 성공하면 Authentication반환 실패는 예외
        return authenticationManager.authenticate(token);

    }

attemptAuthentication() : 로그인 요청이 들어오면 가장 먼저 실행되는 메서드이다.
아이디와 비밀번호를 확인한다.

  • obtainUsername()obtainPassword()를 통해 요청에서 아이디와 비밀번호를 꺼낸다.

    • 이 메서드는 내부적으로 request.getParameter()을 사용하므로 로그인 요청은 form-data (x-www-form-urlencoded)방식으로 전달되어야 한다.
  • new UsernamePasswordAuthenticationToken(username, password, null); : 이후 UsernamePasswordAuthenticationToken을 생성하는데, 이 객체는 아직 인증이 완료되지 않은 상태의 인증 요청 객체이다.

  • authenticationManager.authenticate(token) : 마지막으로 이 메서드를 호출하여 실제 인증을 진행한다.

    • UserDetailService를 통해 사용자 정보를 조회하고
    • PasswordEncoder를 사용하여 비밀번호를 비교한 뒤
    • 인증 성공 시 Authentication 객체를 반환하고, 실패 시 예외를 발생시킨다.
    //로그인 성공시 실행하는 메소드 (여기서 JWT를 발급해야 한다.)
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) {
        System.out.println("success");
        response.setStatus(HttpServletResponse.SC_OK);

    }

    //로그인 실패시 실행하는 메소드
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        System.out.println("fail");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    }

두 메서드는 attemptAuthentication()에서 수행된 인증 결과에 따라 성공과 실패를 처리해준다.

  • successfulAuthentication : AuthenticationManager를 통해 인증이 정상적으로 완료되면, Spring Security는 자동으로 이 메서드를 호출한다.
    • 이 위치에 JWT를 생성하고 클라이언트에게 전달해야한다.
  • unsuccessfulAuthentication : 아이디 또는 비밀번호가 틀린 경우 AuthenticationException이 발생하고, 이 메서드가 호출된다.

전체 동작

  1. 요청: 클라이언트가 POST /login으로 이메일/비번 전송.
  2. LoginFilter가 요청을 낚아채서 attemptAuthentication 실행.
  3. 검증: AuthenticationManager가 CustomUserDetailsService를 시켜 DB에서 유저를 찾고 비밀번호를 비교함.

성공 시: successfulAuthentication 실행 → JWT 발행 → 클라이언트에게 전달.

실패 시: unsuccessfulAuthentication 실행 → 401 에러 응답.

참고영상
https://www.youtube.com/watch?v=3Ff7UHGG3t8&list=PLJkjrxxiBSFCcOjy0AAVGNtIa08VLk1EJ&index=7

0개의 댓글