Week10

아야하면우유·2025년 7월 18일

HSL

목록 보기
6/6
post-thumbnail

JWT와 세션의 차이

  • 세션 : 로그인 -> 난수 생성 -> 세션 저장소에 난수와 해당 로그인 ID를 key - value로 저장 -> 난수는 쿠키에 담아서 클라이언트로 보냄
  • JWT : Header - Payload - Signature로 구성됨. 사용자의 중요한 정보는 담지 않고, 주로 이 서버에서 발행된 토큰인가만 check.

JWT의 구성

  • Header : 어떤 방식으로 암호화됐는지, 이 Authorization은 어떤 방식인지 (여기서는 JWT임)
  • Payload : 간단한 User 정보를 담아줌. 이 정보를 통해 DB에 접근 가능
  • Signature : 어떤 방식으로 암호화됐는지, 어떤 정보가 담겨있는지, Secret Key(서버마다 고유함)를 조합하여 시그니처를 만듬

작동 방식


간단히 말하자면...
1. 로그인 진행
   1-1. 그에 맞는 JWT 발급
2. JWT를 클라이언트에게 전달
3. 이후 인증을 위해서 매번 Header - Authorizaiton으로 JWT 전달
   3-1. Filter단에서 이 JWT를 잡아서 인증하고, 인가(접근 허용)
4. Response를 클라이언트에게 전달


Filter Chain

인증하는 절차는 Filter Chain에 준다.
Spring 공식 문서에 따르면,

  • 클라이언트가 서버에 요청을 보내면 요청 URI를 통하여,
    FilterServlet이 처리해야 할
    HttpServletRequest를 갖고
    FilterChain를 구성한다

필터는 Servlet ContainerDispatcherServlet 사이에 존재한다.

위 그림에서는 HTTP 요청 <- 여기서 이미 FilterChain이 동작한 셈

이 부분이 중요하다.

  • HttpServletRequest : 서버에 온 요청을 담는 객체인데, Header, Cookie, Request Data 등 Request의 모든 정보를 담고 있는 객체이다.
  • 이 객체에서 Header의 Authorization 부분에 JWT를 담는다.
  • How? : Filter에서 로그인을 검증하고, 필수 정보만 담아서 JWT화 하여, Header에 해당 JWT를 담아서 보내는 것이다.

🔥 반드시 지켜져야 하는 흐름

  1. CSRF 보호 필터 - 인증이 살아있는 것을 이용하여 악의적인 요청을 보내지 않도록 보호함
  2. 인증 처리 - 사용자 로그인, JWT 체크 등 (예외는 인증과 인가 사이에서 처리함)
  3. 인가 처리 - RequestMatcher(경로).permitAll() 와 같이 해당 경로의 요청은 인증된 유저만 허용하거나, 모든 유저를 허용케 함

Customizing Filter

 
구현한 코드 내부에서는 form - login 방식을 disable 했고, Param 방식으로 ID와 Password를 받아서 인증하는 방식이었다. 그 중에서
"UsernamePasswordAuthenticationFilter" 라는 것을 덮어쓰기로 했다.
(이름이 다소 길다.)

  • attemptAuthentication : 인증을 시도할 때 사용되는 메서드이다. HttpServletRequest에서 Username과 Password를 받아서 토큰을 만들고 return AuthenticationManager.authenticate(token)를 실행한다.
  • successfulAuthentication : 인증이 성공했을 때 사용하는 메서드이다. CustomUserDetails형으로 유저 정보를 담고, JWT를 만든다. 그리고, Header에 JWT를 담는다.
  • unsuccessfulAuthentication : 인증이 실패했을 때이며, 401 응답을 반환하게끔 구현하였다.

UserDetails

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    default boolean isAccountNonExpired() {
        return true;
    }

    default boolean isAccountNonLocked() {
        return true;
    }

    default boolean isCredentialsNonExpired() {
        return true;
    }

    default boolean isEnabled() {
        return true;
    }
}

UserDetails Interface이다.

  • 이 토큰에서 값을 빼오는 메서드
  • 이 토큰이 만료되었는지 체크하는 메서드
  • 이 토큰이 잠겼는지 체크하는 메서드

등등... Token과 관련된 함수들을 선언해놓는 Interface같다.


끝마치며.

 JWT 구현에 필요한 코드들은 굳이 작성치 않겠다. 아직 모든 함수들을 전부 외운 것도 아니고... 앞으로 더 작성해보며 저절로 외워지길 바랄 따름이다.
 Refrash 토큰과 Access 토큰도 더 공부해봐야 할 것이며, 토큰의 취약점들도 좀 더 공부해볼 생각이다.

profile
우유가 넘어지면 아야

0개의 댓글