From 64f902f14eb2fad5b9f1bfe82e5dfe87b8dcf633 Mon Sep 17 00:00:00 2001 From: NaMinhyeok Date: Thu, 6 Feb 2025 23:26:23 +0900 Subject: [PATCH] =?UTF-8?q?[#66]=20feat:=20=EC=9C=A0=ED=9A=A8=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20duration=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd.yml | 4 ++++ .../domain/auth/model/JwtProperties.java | 20 ++++++++++--------- .../domain/auth/service/JwtProvider.java | 13 +++++------- .../src/main/resources/application.yaml | 4 ++-- .../domain/auth/model/JwtPropertiesTest.java | 13 ++++++------ .../domain/auth/service/JwtParserTest.java | 5 +++-- 6 files changed, 32 insertions(+), 27 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3a24d0d9..d7b5a9db 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -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 @@ -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 diff --git a/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/model/JwtProperties.java b/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/model/JwtProperties.java index b4974e60..65aac581 100644 --- a/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/model/JwtProperties.java +++ b/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/model/JwtProperties.java @@ -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; @@ -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("액세스 토큰의 만료시간은 리프레시 토큰의 만료시간보다 짧아야 합니다."); } } diff --git a/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/service/JwtProvider.java b/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/service/JwtProvider.java index 02a13682..517a5ce3 100644 --- a/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/service/JwtProvider.java +++ b/jaknaeso-server/src/main/java/org/nexters/jaknaesoserver/domain/auth/service/JwtProvider.java @@ -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; @@ -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 claims, final String subject, final Long expirationHours) { + final Map 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(); } diff --git a/jaknaeso-server/src/main/resources/application.yaml b/jaknaeso-server/src/main/resources/application.yaml index 0d4c3b75..aa1cd31d 100644 --- a/jaknaeso-server/src/main/resources/application.yaml +++ b/jaknaeso-server/src/main/resources/application.yaml @@ -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: diff --git a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/model/JwtPropertiesTest.java b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/model/JwtPropertiesTest.java index 5801ec85..89183821 100644 --- a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/model/JwtPropertiesTest.java +++ b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/model/JwtPropertiesTest.java @@ -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; @@ -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)) @@ -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)) @@ -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)) diff --git a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/service/JwtParserTest.java b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/service/JwtParserTest.java index c9523328..37090a63 100644 --- a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/service/JwtParserTest.java +++ b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/auth/service/JwtParserTest.java @@ -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; @@ -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;