Skip to content

Commit 48821f4

Browse files
authored
refactor: Java, SpringBoot 버전 업 & JJWT 버전 업 (#702)
* refactor: Spring Boot, Java 및 주요 의존성 버전업, commons-lang3 추가 - SpringBoot 버전업 (-> 3.5.11) - Java 버전업 (-> 21) - JJWT 버전업 (-> 0.12.6) - 기존 EnumUtils deprecate 대응을 위해 org.apache.commons:commons-lang3 의존성 추가 * refactor: JJWT deprecated API를 신규 API로 마이그레이션 * chore: ci/cd 파일 및 도커파일Java 17 → 21, Spring Boot 버전 업 반영 * test: @MockBean, @spybean을 @MockitoBean, @MockitoSpyBean으로 마이그레이션 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: 누락된 변경사항 추가 * refactor: 코드래빗 리뷰사항 적용 - 테스트에서 Token 생성 시, TTL을 30초로 수정 - TTL이 너무 짧으면 테스트가 간헐적으로 꺠질 위험 존재
1 parent b58d893 commit 48821f4

File tree

24 files changed

+133
-111
lines changed

24 files changed

+133
-111
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
- name: Checkout the code
1616
uses: actions/checkout@v4
1717

18-
- name: Set up JDK 17
18+
- name: Set up JDK 21
1919
uses: actions/setup-java@v4
2020
with:
21-
java-version: '17'
21+
java-version: '21'
2222
distribution: 'temurin'
2323

2424
- name: Setup Gradle

.github/workflows/dev-cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
uses: actions/checkout@v4
2222

2323
# --- Java, Gradle 설정 ---
24-
- name: Set up JDK 17
24+
- name: Set up JDK 21
2525
uses: actions/setup-java@v4
2626
with:
27-
java-version: '17'
27+
java-version: '21'
2828
distribution: 'temurin'
2929
- name: Setup Gradle
3030
uses: gradle/actions/setup-gradle@v3

.github/workflows/prod-cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ jobs:
2727
uses: actions/checkout@v4
2828

2929
# --- Java, Gradle 설정 ---
30-
- name: Set up JDK 17
30+
- name: Set up JDK 21
3131
uses: actions/setup-java@v4
3232
with:
33-
java-version: '17'
33+
java-version: '21'
3434
distribution: 'temurin'
3535
- name: Setup Gradle
3636
uses: gradle/actions/setup-gradle@v3

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# JDK 버전 설정
2-
FROM eclipse-temurin:17-jdk
2+
FROM eclipse-temurin:21-jdk
33

44
# JAR_FILE 변수 정의
55
ARG JAR_FILE=./build/libs/solid-connection-0.0.1-SNAPSHOT.jar

build.gradle

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
plugins {
22
id 'java'
3-
id 'org.springframework.boot' version '3.1.5'
4-
id 'io.spring.dependency-management' version '1.1.4'
5-
id 'org.flywaydb.flyway' version '9.16.3'
3+
id 'org.springframework.boot' version '3.5.11'
4+
id 'io.spring.dependency-management' version '1.1.7'
5+
id 'org.flywaydb.flyway' version '10.15.0'
66
}
77

88
group = 'com.example'
99
version = '0.0.1-SNAPSHOT'
1010

1111
java {
12-
sourceCompatibility = '17'
12+
sourceCompatibility = '21'
1313
}
1414

1515
configurations {
@@ -43,8 +43,9 @@ dependencies {
4343
// Security
4444
implementation 'org.springframework.security:spring-security-config'
4545
implementation 'org.springframework.security:spring-security-web'
46-
implementation 'io.jsonwebtoken:jjwt:0.9.1'
47-
runtimeOnly 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359' // for jjwt
46+
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
47+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
48+
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
4849

4950
// Monitoring
5051
implementation 'org.springframework.boot:spring-boot-starter-actuator'
@@ -70,6 +71,7 @@ dependencies {
7071
implementation 'io.awspring.cloud:spring-cloud-aws-starter-parameter-store:3.0.4'
7172
implementation 'org.hibernate.validator:hibernate-validator'
7273
implementation 'org.springframework.boot:spring-boot-starter-websocket'
74+
implementation 'org.apache.commons:commons-lang3'
7375

7476
// Database Proxy
7577
implementation 'net.ttddyy.observation:datasource-micrometer:1.2.0'

claude.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
Solid Connect Server는 교환학생 준비생을 위해 대학 정보, 멘토 매칭, 모의지원 기능 등을 제공하는 교환학생 지원 통합 플랫폼입니다.
99

10-
- **언어**: Java 17
11-
- **프레임워크**: Spring Boot 3.1.5
10+
- **언어**: Java 21
11+
- **프레임워크**: Spring Boot 3.5.11
1212
- **빌드 도구**: Gradle
1313
- **데이터베이스**: MySQL (주), Redis (캐싱)
1414
- **마이그레이션**: Flyway

src/main/java/com/example/solidconnection/auth/client/AppleOAuthClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ private MultiValueMap<String, String> buildFormData(String code) {
8181
private String parseEmailFromToken(PublicKey applePublicKey, String idToken) {
8282
try {
8383
return Jwts.parser()
84-
.setSigningKey(applePublicKey)
85-
.parseClaimsJws(idToken)
86-
.getBody()
84+
.verifyWith(applePublicKey)
85+
.build()
86+
.parseSignedClaims(idToken)
87+
.getPayload()
8788
.get("email", String.class);
8889
} catch (Exception e) {
8990
throw new CustomException(INVALID_APPLE_ID_TOKEN);

src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55
import com.example.solidconnection.auth.client.config.AppleOAuthClientProperties;
66
import com.example.solidconnection.common.exception.CustomException;
77
import io.jsonwebtoken.Jwts;
8-
import io.jsonwebtoken.SignatureAlgorithm;
98
import jakarta.annotation.PostConstruct;
109
import java.security.KeyFactory;
1110
import java.security.NoSuchAlgorithmException;
1211
import java.security.PrivateKey;
1312
import java.security.spec.InvalidKeySpecException;
1413
import java.security.spec.PKCS8EncodedKeySpec;
14+
import java.util.Base64;
1515
import java.util.Date;
1616
import lombok.RequiredArgsConstructor;
17-
import org.apache.tomcat.util.codec.binary.Base64;
1817
import org.springframework.stereotype.Component;
1918

2019
/*
@@ -42,20 +41,19 @@ public String generateClientSecret() {
4241
Date expiration = new Date(now.getTime() + TOKEN_DURATION);
4342

4443
return Jwts.builder()
45-
.setHeaderParam("alg", "ES256")
46-
.setHeaderParam(KEY_ID_HEADER, appleOAuthClientProperties.keyId())
47-
.setSubject(appleOAuthClientProperties.clientId())
48-
.setIssuer(appleOAuthClientProperties.teamId())
49-
.setAudience(appleOAuthClientProperties.clientSecretAudienceUrl())
50-
.setExpiration(expiration)
51-
.signWith(SignatureAlgorithm.ES256, privateKey)
44+
.header().add(KEY_ID_HEADER, appleOAuthClientProperties.keyId()).and()
45+
.subject(appleOAuthClientProperties.clientId())
46+
.issuer(appleOAuthClientProperties.teamId())
47+
.audience().add(appleOAuthClientProperties.clientSecretAudienceUrl()).and()
48+
.expiration(expiration)
49+
.signWith(privateKey, Jwts.SIG.ES256)
5250
.compact();
5351
}
5452

5553
private PrivateKey loadPrivateKey() {
5654
try {
5755
String secretKey = appleOAuthClientProperties.secretKey();
58-
byte[] encoded = Base64.decodeBase64(secretKey);
56+
byte[] encoded = Base64.getMimeDecoder().decode(secretKey);
5957
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
6058
KeyFactory keyFactory = KeyFactory.getInstance("EC");
6159
return keyFactory.generatePrivate(keySpec);

src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
import com.example.solidconnection.auth.token.config.JwtProperties;
88
import com.example.solidconnection.common.exception.CustomException;
99
import io.jsonwebtoken.Claims;
10+
import io.jsonwebtoken.JwtBuilder;
1011
import io.jsonwebtoken.Jwts;
11-
import io.jsonwebtoken.SignatureAlgorithm;
12+
import io.jsonwebtoken.security.Keys;
13+
import java.nio.charset.StandardCharsets;
1214
import java.time.Duration;
1315
import java.util.Date;
1416
import java.util.Map;
17+
import javax.crypto.SecretKey;
1518
import lombok.RequiredArgsConstructor;
1619
import org.springframework.stereotype.Component;
1720

@@ -32,16 +35,18 @@ public String generateToken(Subject subject, Map<String, String> customClaims, D
3235
}
3336

3437
private String generateJwtTokenValue(String subject, Map<String, String> claims, Duration expireTime) {
35-
Claims jwtClaims = Jwts.claims().setSubject(subject);
36-
jwtClaims.putAll(claims);
3738
Date now = new Date();
3839
Date expiredDate = new Date(now.getTime() + expireTime.toMillis());
39-
return Jwts.builder()
40-
.setClaims(jwtClaims)
41-
.setIssuedAt(now)
42-
.setExpiration(expiredDate)
43-
.signWith(SignatureAlgorithm.HS512, jwtProperties.secret())
44-
.compact();
40+
JwtBuilder builder = Jwts.builder()
41+
.subject(subject)
42+
.issuedAt(now)
43+
.expiration(expiredDate);
44+
claims.forEach(builder::claim);
45+
return builder.signWith(getSigningKey()).compact();
46+
}
47+
48+
private SecretKey getSigningKey() {
49+
return Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(StandardCharsets.UTF_8));
4550
}
4651

4752
@Override
@@ -61,9 +66,10 @@ public <T> T parseClaims(String token, String claimName, Class<T> claimType) {
6166
private Claims parseJwtClaims(String token) {
6267
try {
6368
return Jwts.parser()
64-
.setSigningKey(jwtProperties.secret())
65-
.parseClaimsJws(token)
66-
.getBody();
69+
.verifyWith(getSigningKey())
70+
.build()
71+
.parseSignedClaims(token)
72+
.getPayload();
6773
} catch (Exception e) {
6874
throw new CustomException(INVALID_TOKEN);
6975
}

src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import org.junit.jupiter.api.Nested;
3030
import org.junit.jupiter.api.Test;
3131
import org.springframework.beans.factory.annotation.Autowired;
32-
import org.springframework.boot.test.mock.mockito.SpyBean;
32+
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
3333
import org.springframework.data.domain.Page;
3434
import org.springframework.data.domain.PageRequest;
3535

@@ -55,7 +55,7 @@ class AdminHostUniversityServiceTest {
5555
@Autowired
5656
private UnivApplyInfoFixtureBuilder univApplyInfoFixtureBuilder;
5757

58-
@SpyBean
58+
@MockitoSpyBean
5959
private CustomCacheManager cacheManager;
6060

6161
@Nested

0 commit comments

Comments
 (0)