Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Kuma's Curious Paradise

[이룸] 240229 JwtAuthenticationFilter.java 본문

이룸 프로젝트

[이룸] 240229 JwtAuthenticationFilter.java

쿠마냥 2024. 3. 7. 15:33
  1. 클래스명의 이유
    • JwtAuthenticationFilter : jwt 토큰으로 Authentication(인증)을 하는 Filter 클래스.
    FIlter 인터페이스 → **Generic Filter Bean** 추상 클래스 → **AbstractAuthenticationProcessingFilter** 추상 클래스 → **UsernamePasswordAuthenticationFilter** 추상 클래스 → JwtAuthenticationFilter 클래스. ****
    • Filter란? 반복적으로 들어오는 객체에서 특정 조건을 걸러내는 역할을 함. servlet 컨테이너 입구에서 인코딩, 로깅, 인증과 같은 전역 작업을 처리하며, filter와 비슷한 역할을 하는 것에는 interceptor와 AOP가 있음.
    • UsernamePasswordAuthenticationFilter란? id와 password를 사용하여 인증을 처리하는 데 사용되는 필터. HTTP 요청에서 id와 password 추출해서 Authentication 객체를 생성하고, 해당 객체를 AuthenticationManager에게 전달하여 인증을 시도.
  2. 클래스에 붙은 어노테이션
    • **@Slf4j(topic = "로그인 및 JWT 생성")** : Logger 객체를 자동으로 생성하여 log.info() 와 같은 메서드를 쓸 수 있게 해 주는 lombok 라이브러리의 일부. topic 속성을 통해 로거의 이름을 지정할 수 있음.

의존성 주입

public JwtAuthenticationFilter(JwtUtil jwtUtil) {
    this.jwtUtil = jwtUtil;
    setFilterProcessesUrl("/api/login");
}
  • setFilterProcessesUrl("/api/login"); : 해당 필터가 요청을 처리해야 하는 url을 설정하는 메서드. 쉽게 말하면 /api/login 으로 요청이 들어오면 이 필터를 실행시킴.
  • 일반적으로 필터 생성자에서 의존성 주입과 작동 url을 함께 설정함. 어떤 종류의 인증 작업을 수행하는지, 어떤 Url에서 동작하는지 한눈에 파악할 수 있기 때문이라고 함.
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

    try {
        LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
        log.info("로그인 시도 - 사용자: {}", requestDto.getEmail());

        return getAuthenticationManager().authenticate(
                new UsernamePasswordAuthenticationToken(
                        requestDto.getEmail(),
                        requestDto.getPassword()
                )
        );
    } catch (IOException e) {
        log.error("로그인 시도 중 오류 발생: {}", e.getMessage());
        throw new AuthenticationServiceException("로그인 시도 중 오류가 발생했습니다.", e);
    }
}

 

  • @Override: UsernamePasswordAuthenticationFilter 클래스의 attemptAuthentication() 메서드를 오버라이드
  • HttpServletRequest 객체로부터 요청을 처리하고, 사용자가 제공한 로그인 정보를 추출
  • **LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);** :
    request.getInputStream()으로 http 요청에서 body를 읽어냄. → readValue()로 해당 JSON 데이터를 Java 객체(여기서는 LoginRequestDto 클래스의 객체)로 변환. jackson 라이브러리에서 제공하는 ObjectMapper 클래스 메서드 중 하나. → 쉽게 말해, **ObjectMapper**를 사용하여 JSON을 Java 객체로 매핑하는 과정
  • getAuthenticationManager()로 인증 매니저 호출. 이 매니저는 인증 객체를 생성하고 인증을 시도하는 역할. → authenticate() 메서드를 호출하여 사용자명과 비밀번호를 가진 UsernamePasswordAuthenticationToken 객체를 생성하여 인증 매니저에게 전달 → 인증 매니저는 전달된 인증 객체를 사용하여 사용자를 인증하고, 인증 결과를 반환
  • 만약 로그인 시도 중에 예외가 발생하면, 해당 예외를 catch하여 로그에 오류를 기록하고**AuthenticationServiceException**을 던짐
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
    String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
    MemberRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getMember().getRole();
    String accessToken = jwtUtil.createAccessToken(username, role);
    String refreshToken = jwtUtil.createRefreshToken(username);

    jwtUtil.addJwtToCookie(accessToken, response, JwtUtil.AUTHORIZATION_HEADER);
    jwtUtil.addJwtToCookie(refreshToken, response, JwtUtil.REFRESH_TOKEN_HEADER);

    log.info("사용자 '{}'의 로그인 성공 및 JWT 생성", username);
}
  • **String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();** : Authentication 객체인 authResult를 파라미터로 받음. → getPrincipal() 호출하여 사용자의 인증 정보, principal 객체 추출 → authentication provider는 이 principal 객체를 userDetails 객체로 바꿔줌 → (UserDetailsImpl) 객체로 업캐스팅 → 이후 getUsername() 호출하여 username 추출

이후 같은 방식으로 사용자의 역할을 추출→ accessToken과 refreshToken 생성 → 쿠키에 담기

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
    log.info("로그인 실패 - {}", failed.getMessage());
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
  • 로그인에 실패하면 401 반환