memostack
article thumbnail
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형

dependency 추가

mvnrepository.com/artifact/io.jsonwebtoken/jjwt/0.9.1

<dependencies>
    ...
    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    ...
</dependencies>

 

JWT 토큰 생성하기

JwtManager라는 Bean을 생성한다.

  • 공통으로 쓸것이기 때문에 IoC에 담아두고 써도 무관
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtManager {
  private final String securityKey = "hello world"; // TODO 민감정보는 따로 분리하는 것이 좋다
  private final Long expiredTime = 1000 * 60L * 60L * 3L; // 유효시간 3시간

  /**
   * Member 정보를 담은 JWT 토큰을 생성한다.
   *
   * @param member Member 정보를 담은 객체
   * @return String JWT 토큰
   */
  public String generateJwtToken(Member member) {
    Date now = new Date();
    return Jwts.builder()
        .setSubject(member.getUsername()) // 보통 username
        .setHeader(createHeader())
        .setClaims(createClaims(member)) // 클레임, 토큰에 포함될 정보
        .setExpiration(new Date(now.getTime() + expiredTime)) // 만료일
        .signWith(SignatureAlgorithm.HS256, securityKey)
        .compact();
  }

  private Map<String, Object> createHeader() {
    Map<String, Object> header = new HashMap<>();
    header.put("typ", "JWT");
    header.put("alg", "HS256"); // 해시 256 사용하여 암호화
    header.put("regDate", System.currentTimeMillis());
    return header;
  }

  /**
   * 클레임(Claim)을 생성한다.
   *
   * @param member 토큰을 생성하기 위한 계정 정보를 담은 객체
   * @return Map<String, Object> 클레임(Claim)
   */
  private Map<String, Object> createClaims(Member member) {
    Map<String, Object> claims = new HashMap<>();
    claims.put("username", member.getUsername()); // username
    claims.put("roles", member.getMemberRoles()); // 인가정보
    return claims;
  }
}
  • Member는 단순히 username, password, role 등의 정보를 담은 엔티티라서 생략한다.

 

토큰으로부터 정보 가져오기

그리고, 토큰으로 부터 정보를 가지고 오는 코드를 작성해보자

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Component
public class JwtManager {
  private final String securityKey = "hello world";
  
  //...중략...

  /**
   * Token 에서 Claim 을 가져온다.
   *
   * @param token JWT 토큰
   * @return Claims 클레임
   */
  private Claims getClaims(String token) {
    return Jwts.parser().setSigningKey(securityKey).parseClaimsJws(token).getBody();
  }

  /**
   * 토큰으로 부터 username 을 가져온다.
   *
   * @param token JWT 토큰
   * @return String Member 의 username
   */
  public String getUsernameFromToken(String token) {
    return (String) getClaims(token).get("username");
  }

  /**
   * 토큰으로 부터 인가 정보를 가져온다.
   *
   * @param token JWT 토큰
   * @return Set<MemberRole> role 정보를 가지고 있는 Set
   */
  public Set<MemberRole> getMemberRoleSetFromToken(String token) {
    return (Set<MemberRole>) getClaims(token).get("roles");
  }
}

 

 

기능 확인

토큰을 생성하고, 생성된 토큰으로부터 다시 정보를 가지고 온다.

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("JwtManger 테스트")
class JwtManagerTest {

  private JwtManager jwtManager;

  @BeforeEach
  void setUp() {
    jwtManager = new JwtManager();
  }

  @Test
  @DisplayName("토큰 생성 및 복호화 테스트")
  void tokenTest() {
    // given
    LocalDateTime now = LocalDateTime.now();
    final Member member =
        Member.builder()
            .username("hong01")
            .password("1234")
            .name("hong")
            .email("hong@gmail.com")
            .phone("010-1234-5678")
            .registerAt(now)
            .passwordUpdatedAt(now)
            .isActive(true)
            .build();

    // when
    // 1) 토큰 생성
    final String token = jwtManager.generateJwtToken(member);
    // 2) 토큰으로부터 username 가져오기
    String usernameFromToken = jwtManager.getUsernameFromToken(token);

    // then
    assertEquals("hong01", usernameFromToken);
  }
}

테스트 성공

반응형
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
profile

memostack

@bluemiv_mm

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!