Skip to content

Commit 1c5c5c4

Browse files
committed
feat: TokenManager 구현
1 parent 166bc47 commit 1c5c5c4

File tree

1 file changed

+56
-5
lines changed

1 file changed

+56
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,65 @@
11
package com.wooteco.wiki.domain;
22

33
import com.wooteco.wiki.exception.WrongTokenException;
4+
import io.jsonwebtoken.Claims;
5+
import io.jsonwebtoken.Jws;
6+
import io.jsonwebtoken.JwtException;
7+
import io.jsonwebtoken.Jwts;
8+
import io.jsonwebtoken.security.Keys;
9+
import java.time.Instant;
10+
import java.time.LocalDateTime;
11+
import java.time.ZoneId;
12+
import java.util.Date;
413
import org.springframework.beans.factory.annotation.Value;
514
import org.springframework.stereotype.Component;
615

716
@Component
817
public class TokenManager {
18+
private static final String MEMBER_ID = "member_id";
19+
private static final String TOKEN_TYPE = "token_type";
20+
private static final long ACCESS_TOKEN_LIFE_TIME_AS_HOUR = 1;
21+
private static final long REFRESH_TOKEN_LIFE_TIME_AS_HOUR = 24;
922
@Value("${jwt.key}")
1023
private String secretKey;
1124

1225
/**
13-
* 생성된 엑세스 토큰은 리프레쉬 토큰으로 사용할 수 없어야 함. 엑세스 토큰에는 회원의 식별자를 제외한 다른 개인 정보가 포함되면 안됨.
26+
* 생성된 엑세스 토큰은 리프레쉬 토큰으로 사용할 수 없어야 함. 엑세스 토큰에는 회원의 식별자를 제외한 다른 개인 정보가 포함되면 안됨. 우선 엑세스 토큰 유효 시간은 발급 시점으로부터 1시간으로 설정함.
27+
* 논의 후 조정하기로!
1428
*
1529
* @param member 회원 도메인
1630
* @return 엑세스 토큰
1731
*/
1832
public String generateAccessToken(Member member) {
19-
return null;
33+
LocalDateTime rawExpiredTime = LocalDateTime.now().plusHours(ACCESS_TOKEN_LIFE_TIME_AS_HOUR);
34+
Date expiredTime = localDateTimeToDate(rawExpiredTime);
35+
return Jwts.builder()
36+
.expiration(expiredTime)
37+
.claim(TOKEN_TYPE, "access")
38+
.claim(MEMBER_ID, member.getMemberId())
39+
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
40+
.compact();
41+
}
42+
43+
private Date localDateTimeToDate(LocalDateTime expiredTime) {
44+
Instant instant = expiredTime.atZone(ZoneId.systemDefault()).toInstant();
45+
return Date.from(instant);
2046
}
2147

2248
/**
23-
* 생성된 리프레쉬 토큰은 엑세스 토큰으로 사용할 수 없어야 함.
49+
* 생성된 리프레쉬 토큰은 엑세스 토큰으로 사용할 수 없어야 함. 우선 리프레쉬 토큰 유효 시간은 발급 시점으로부터 1일로 설정함. 논의 후 조정하기로!
2450
*
2551
* @param member 회원 도메인
2652
* @return 리프레쉬 토큰
2753
*/
2854
public String generateRefreshToken(Member member) {
29-
return null;
55+
LocalDateTime rawExpiredTime = LocalDateTime.now().plusHours(REFRESH_TOKEN_LIFE_TIME_AS_HOUR);
56+
Date expiredTime = localDateTimeToDate(rawExpiredTime);
57+
return Jwts.builder()
58+
.expiration(expiredTime)
59+
.claim(TOKEN_TYPE, "refresh")
60+
.claim(MEMBER_ID, member.getMemberId())
61+
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
62+
.compact();
3063
}
3164

3265
/**
@@ -37,6 +70,24 @@ public String generateRefreshToken(Member member) {
3770
* @throws WrongTokenException 엑세스 토큰에 문제(잘못된 토큰, 기간 만료 등)가 있어 회원 식별자를 추출할 수 없는 경우
3871
*/
3972
public long extractMemberId(String accessToken) throws WrongTokenException {
40-
return -1;
73+
try {
74+
Jws<Claims> claimsJws = Jwts.parser()
75+
.verifyWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
76+
.build()
77+
.parseSignedClaims(accessToken);
78+
79+
Claims payload = claimsJws.getPayload();
80+
validateTokenIsAccessToken(payload);
81+
return payload.get(MEMBER_ID, Long.class);
82+
} catch (JwtException | IllegalArgumentException e) {
83+
throw new WrongTokenException("잘못된 토큰입니다.");
84+
}
85+
}
86+
87+
private static void validateTokenIsAccessToken(Claims payload) {
88+
String tokenType = payload.get(TOKEN_TYPE, String.class);
89+
if (!tokenType.equals("access")) {
90+
throw new WrongTokenException("엑세스 토큰이 아닙니다.");
91+
}
4192
}
4293
}

0 commit comments

Comments
 (0)