Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(#66): 토큰 유효시간 설정 #67

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ env:
NCP_SERVER_HOST: ${{ secrets.NCP_SERVER_HOST }}
NCP_SERVER_USERNAME: ${{ secrets.NCP_SERVER_USERNAME }}
NCP_SERVER_PASSWORD: ${{ secrets.NCP_SERVER_PASSWORD }}
ACCESS_TOKEN_EXPIRATION: ${{ secrets.ACCESS_TOKEN_EXPIRATION }}
REFRESH_TOKEN_EXPIRATION: ${{ secrets.REFRESH_TOKEN_EXPIRATION }}
SSH_PORT: 22
BUILD_NUMBER: ${{ github.sha }}-${{ github.run_id }}
SPRING_PROFILES_ACTIVE: dev
Expand Down Expand Up @@ -81,6 +83,8 @@ jobs:
echo "DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD }}" >> .env
echo "DATABASE_ROOT_PASSWORD=${{ secrets.DATABASE_ROOT_PASSWORD }}" >> .env
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
echo "ACCESS_TOKEN_EXPIRATION=${{ env.ACCESS_TOKEN_EXPIRATION }}" >> .env
echo "REFRESH_TOKEN_EXPIRATION=${{ env.REFRESH_TOKEN_EXPIRATION }}" >> .env
echo "KAKAO_LOGIN_CLIENT_ID=${{ secrets.KAKAO_LOGIN_CLIENT_ID }}" >> .env
echo "KAKAO_LOGIN_CLIENT_SECRET=${{ secrets.KAKAO_LOGIN_CLIENT_SECRET }}" >> .env
echo "SPRING_PROFILES_ACTIVE=${{ env.SPRING_PROFILES_ACTIVE }}" >> .env
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.nexters.jaknaesoserver.domain.auth.model;

import io.jsonwebtoken.security.Keys;
import java.time.Duration;
import javax.crypto.SecretKey;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
Expand All @@ -9,24 +10,25 @@
@ConfigurationProperties(prefix = "jwt")
public class JwtProperties {
private final String secret;
private final Long accessTokenExpirationHours;
private final Long refreshTokenExpirationHours;
private final Duration accessTokenExpiration;
private final Duration refreshTokenExpiration;
private final SecretKey secretKey;

public JwtProperties(
String secret, Long accessTokenExpirationHours, Long refreshTokenExpirationHours) {
validateTokenExpirations(accessTokenExpirationHours, refreshTokenExpirationHours);
String secret, Duration accessTokenExpiration, Duration refreshTokenExpiration) {
validateTokenExpirations(accessTokenExpiration, refreshTokenExpiration);
this.secret = secret;
this.accessTokenExpirationHours = accessTokenExpirationHours;
this.refreshTokenExpirationHours = refreshTokenExpirationHours;
this.accessTokenExpiration = accessTokenExpiration;
this.refreshTokenExpiration = refreshTokenExpiration;
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes());
}

private void validateTokenExpirations(Long accessTokenExpiration, Long refreshTokenExpiration) {
if (accessTokenExpiration <= 0 || refreshTokenExpiration <= 0) {
private void validateTokenExpirations(
Duration accessTokenExpiration, Duration refreshTokenExpiration) {
if (accessTokenExpiration.isZero() || refreshTokenExpiration.isZero()) {
throw new IllegalArgumentException("토큰의 만료시간은 0보다 커야 합니다.");
}
if (accessTokenExpiration >= refreshTokenExpiration) {
if (accessTokenExpiration.compareTo(refreshTokenExpiration) >= 0) {
throw new IllegalArgumentException("액세스 토큰의 만료시간은 리프레시 토큰의 만료시간보다 짧아야 합니다.");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.nexters.jaknaesoserver.domain.auth.service;

import io.jsonwebtoken.Jwts;
import java.time.Duration;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import org.nexters.jaknaesoserver.domain.auth.model.JwtProperties;
import org.springframework.stereotype.Component;
Expand All @@ -15,25 +15,22 @@ public class JwtProvider {
private final JwtProperties jwtProperties;

public String generateAccessToken(final Long userId) {
return generateToken(
Map.of(), userId.toString(), jwtProperties.getAccessTokenExpirationHours());
return generateToken(Map.of(), userId.toString(), jwtProperties.getAccessTokenExpiration());
}

public String generateRefreshToken(final Long userId) {
return generateToken(
Map.of(), userId.toString(), jwtProperties.getRefreshTokenExpirationHours());
return generateToken(Map.of(), userId.toString(), jwtProperties.getRefreshTokenExpiration());
}

private String generateToken(
final Map<String, Object> claims, final String subject, final Long expirationHours) {
final Map<String, Object> claims, final String subject, final Duration expirationDuration) {
Date now = new Date();
long expirationMillis = TimeUnit.HOURS.toMillis(expirationHours);

return Jwts.builder()
.claims(claims)
.subject(subject)
.issuedAt(now)
.expiration(new Date(now.getTime() + expirationMillis))
.expiration(new Date(now.getTime() + expirationDuration.toMillis()))
.signWith(jwtProperties.getSecretKey())
.compact();
}
Expand Down
4 changes: 2 additions & 2 deletions jaknaeso-server/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ cors:

jwt:
secret: ${JWT_SECRET}
access-token-expiration-hours: 1
refresh-token-expiration-hours: 240
access-token-expiration: ${ACCESS_TOKEN_EXPIRATION:PT1M}
refresh-token-expiration: ${REFRESH_TOKEN_EXPIRATION:P30D}

oauth:
kakao:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.nexters.jaknaesoserver.domain.auth.model;

import java.time.Duration;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -11,8 +12,8 @@ class JwtPropertiesTest {
void 액세스_토큰_만료시간은_0보다_커야_한다() {
// given
String secret = "thisIsTestSecretKeyShouldBeLongEnoughForHS512";
Long accessTokenExpiration = 0L;
Long refreshTokenExpiration = 36000000000L;
Duration accessTokenExpiration = Duration.ZERO;
Duration refreshTokenExpiration = Duration.ofDays(1);
// when & then
Assertions.assertThatIllegalArgumentException()
.isThrownBy(() -> new JwtProperties(secret, accessTokenExpiration, refreshTokenExpiration))
Expand All @@ -24,8 +25,8 @@ class JwtPropertiesTest {
void 리프레시_토큰_만료시간은_0보다_커야_한다() {
// given
String secret = "thisIsTestSecretKeyShouldBeLongEnoughForHS512";
Long accessTokenExpiration = 0L;
Long refreshTokenExpiration = 0L;
Duration accessTokenExpiration = Duration.ZERO;
Duration refreshTokenExpiration = Duration.ZERO;
// when & then
Assertions.assertThatIllegalArgumentException()
.isThrownBy(() -> new JwtProperties(secret, accessTokenExpiration, refreshTokenExpiration))
Expand All @@ -37,8 +38,8 @@ class JwtPropertiesTest {
void 액세스_토큰_만료시간은_리프레시_토큰_만료시간보다_짧아야_한다() {
// given
String secret = "thisIsTestSecretKeyShouldBeLongEnoughForHS512";
Long accessTokenExpiration = 1000L;
Long refreshTokenExpiration = 999L;
Duration accessTokenExpiration = Duration.ofHours(1);
Duration refreshTokenExpiration = Duration.ofHours(1);
// when & then
Assertions.assertThatIllegalArgumentException()
.isThrownBy(() -> new JwtProperties(secret, accessTokenExpiration, refreshTokenExpiration))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

import io.jsonwebtoken.Jwts;
import java.time.Duration;
import java.util.Date;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -13,8 +14,8 @@

class JwtParserTest {
private static final String SECRET = "thisIsTestSecretKeyShouldBeLongEnoughForHS512";
private static final Long ACCESS_TOKEN_EXPIRATION = 3600000L;
private static final Long REFRESH_TOKEN_EXPIRATION = 1209600000L;
private static final Duration ACCESS_TOKEN_EXPIRATION = Duration.ofDays(1);
private static final Duration REFRESH_TOKEN_EXPIRATION = Duration.ofDays(30);

private JwtParser jwtParser;
private JwtProperties jwtProperties;
Expand Down
Loading