블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.github.io/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형
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);
}
}
반응형
'Backend > Spring Boot' 카테고리의 다른 글
JPA Fetch 종류 (LAZY Fetch와 EAGER Fetch) (0) | 2021.03.27 |
---|---|
Spring Boot에서 AOP 구현 (Aspect Oriented Programming) (0) | 2021.03.11 |
SpringBoot, Junit5에서 REST API(Controller) 테스트 (0) | 2021.01.15 |
SpringBoot, Junit5에서 Service 테스트 (1) | 2021.01.13 |
SpringBoot, Junit5에서 JPA Repository 테스트 (0) | 2021.01.06 |