토큰을 파싱하는 Parser 개발

Seung jun Cha·2024년 7월 14일
0

JwtTokenParser 클래스

  • JWT 토큰을 파싱하고, 인증 정보를 추출하며, 토큰의 유효성을 검증하는 역할을 하는 기능을 하는 클래스이다.

  • refreshTokenQuery: 리프레시 토큰을 조회하기 위한 서비스 클래스이다. 책임을 명확하게 분리하고 쉬운 테스트를 위해 RefreshTokenRepository 클래스와 refreshTokenQuery 클래스를 분리했다.

  • RefreshTokenQuery의 findByValue, existsByValue 메서드는 리프레쉬토큰 값으로 해당 토큰의 존재여부과 토큰을 가져오는 메서드이다.

  • 다음 JwtParser는 JWT 토큰을 파싱하기 위한 JwtParser 객체이다. 이 코드에서 jwtParser는 JWT의 서명 키를 설정하여 초기화한다.


  • extractAuthentication메서드는 토큰에서 사용자 인증 정보를 추출하는 메서드이다. jwtParser를 이용해 클레임을 추출하고 클레임에서 권한 목록을 추출. 그걸 GrantedAuthority 객체로 변환한다.

  • JwtTokenProvider.AUTHORITIES_KEY를 key로 하는 value를 가져온다. 토큰을 생성하는 코드를 다시 보면
    claims.get(JwtTokenProvider.AUTHORITIES_KEY).toString()

  • extractAuthentication메서드를 보면 claim에서 key를 바탕으로 권한목록 추출한 것을 string으로 바꾼다.

claims.get(JwtTokenProvider.AUTHORITIES_KEY).toString().split(JwtTokenProvider.AUTHORITIES_DELIMITER)

그렇게 만들어진 문자열을 구분자를 기준으로 split 하고 문자열 배열을 생성한다. 여기서 Arrays.stream은 문자열 배열을 스트림으로 변환한다.
Arrays.stream(claims.get(JwtTokenProvider.AUTHORITIES_KEY).toString().split(JwtTokenProvider.AUTHORITIES_DELIMITER))

  • map(SimpleGrantedAuthority::new)는 스트림의 각 요소(즉, 각 권한 문자열)를 SimpleGrantedAuthority 객체로 변환한다. SimpleGrantedAuthority는 Spring Security에서 권한을 나타내기 위해 사용된다.

.map(SimpleGrantedAuthority::new)

  • 스트림의 모든 요소를 리스트(List)로 수집해서 결과로 권한 정보가 담긴 GrantedAuthority 객체들의 리스트가 생성된다.

.collect(Collectors.toList());

  • 이 과정을 통해 JWT 토큰에서 추출한 권한 정보를 Spring Security가 이해할 수 있는 GrantedAuthority 객체들로 변환하여, 인증 객체(Authentication)에 사용할 수 있게 된다.
  1. jwtParser로 토큰 claim 추출
  2. claim에서 key를 바탕으로 권한목록 추출
  3. 구분자를 기준으로 나누고 문자열 배열을 생성
  4. 생성된 문자열 배열을 Arrays.stream이 스트림으로 변환
  5. 스트림의 각 요소(권한 문자열)을 SimpleGrantedAuthority 객체로 변환
  6. SimpleGrantedAuthority 객체를 리스트화
  • 그 아래에 있는 코드는 JWT 토큰에서 추출한 권한 정보를 이용하여 Spring Security에서 사용할 수 있는 인증 객체를 생성하는 부분이다.

User.builder() : User 클래스는 Spring Security에서 제공하는 UserDetails 인터페이스의 기본 구현체이다.

.username(claims.getSubject()) : JWT 토큰의 클레임에서 주체(subject)를 가져온다. 주체(subject)는 일반적으로 사용자명을 의미한다.

.password("N/A"): : JWT 토큰으로부터 인증 정보를 추출하는 과정에서 비밀번호가 필요하지 않기 때문에 "N/A"와 같은 임의의 값을 설정한다. 실제로 이 값은 인증 과정에서는 사용되지 않는다. 비밀번호가 필요하지 않은 이유는 사용자가 로그인할 때, 서버는 사용자의 아이디와 비밀번호를 입력해서 로그인하면 JWT 토큰을 발급한다. 이후 요청에서는 JWT 토큰의 유효성을 검사해서 사용자를 인증하기 때문에 사용자 정보를 의미하는 UserDetails 객체에 비밀번호가 들어갈 필요가 없다. (비밀번호 검증은 이미 로그인 과정에서 완료)

.authorities(authorities) : 이전 코드에서 생성한 GrantedAuthority 객체들의 리스트로 사용자에게 부여된 권한을 의미한다.

return new UsernamePasswordAuthenticationToken(principal, token, authorities);

  • 각 파라미터의 의미이다.

    • principal은 인증된 사용자 정보
    • token은 JWT 토큰으로, 인증의 자격 증명(credentials) 역할
    • authorities는 사용자에게 부여된 권한 정보
  • 다음은 토큰을 파싱해서 해당 토큰이 유효한지 알아보는 메서드이다.

  • Claims claims = jwtParser.parseClaimsJws(token).getBody(); : 토큰을 파싱해서 claim 을 가져온다.

  • boolean isTokenExpired = claims.getExpiration().before(new Date()); : 지금 날짜, 시간과 비교해서 토큰이 유효한지 아닌지 판단한다.

  • boolean isTokenTypeMatch = tokenType.name().equals(claims.get(JwtTokenProvider.TOKEN_TYPE_KEY)); : 토큰의타입이 일치하는지 검사한다.

  • 엑세스토큰은 유효기간이 만료됐는지, 리프레쉬토큰은 유효기간과 redis에 토큰이 존재하는지 여부까지 판단한다.

0개의 댓글