Spring Security의 기본 로그인 필터를 커스터마이징한 필터로,
로그인 요청을 가로채 인증을 수행하는 역할을 한다.
Spring Security는 기본적으로 UsernamePasswordAuthenticationFilter를 사용하여 로그인을 처리한다.
하지만 JWT 기반 인증을 적용하려면 로그인 성공 시 JWT를 발급해야하기 때문에 기본 필터를 그대로 사용할 수 없다.
따라서 기본 로그인 필터를 상속받아 LoginFilter를 직접 구현해야한다.
public class LoginFilter extends UsernamePasswordAuthenticationFilter
죽, 기존 로그인 필터를 확장하여 커스터마이징한 것이다.
기본 로그인 흐름은 다음과 같다.
로그인 요청 → 인증 → 세션 저장
하지만 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) : 마지막으로 이 메서드를 호출하여 실제 인증을 진행한다.
//로그인 성공시 실행하는 메소드 (여기서 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는 자동으로 이 메서드를 호출한다.unsuccessfulAuthentication : 아이디 또는 비밀번호가 틀린 경우 AuthenticationException이 발생하고, 이 메서드가 호출된다.POST /login으로 이메일/비번 전송.LoginFilter가 요청을 낚아채서 attemptAuthentication 실행.AuthenticationManager가 CustomUserDetailsService를 시켜 DB에서 유저를 찾고 비밀번호를 비교함.성공 시: successfulAuthentication 실행 → JWT 발행 → 클라이언트에게 전달.
실패 시: unsuccessfulAuthentication 실행 → 401 에러 응답.
참고영상
https://www.youtube.com/watch?v=3Ff7UHGG3t8&list=PLJkjrxxiBSFCcOjy0AAVGNtIa08VLk1EJ&index=7