refactor: Java, SpringBoot 버전 업 & JJWT 버전 업#702
Conversation
- SpringBoot 버전업 (-> 3.5.11) - Java 버전업 (-> 21) - JJWT 버전업 (-> 0.12.6) - 기존 EnumUtils deprecate 대응을 위해 org.apache.commons:commons-lang3 의존성 추가
Walkthrough
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
claude.md (1)
170-170:⚠️ Potential issue | 🟡 Minor2. 문서 내 Spring Boot 버전 불일치 발견 📝
Line 11에서는
Spring Boot 3.5.11로 업데이트되었지만, "기술 스택 상세" 섹션(Line 170)에서는 여전히Spring Boot 3.1.5로 표기되어 있습니다. 문서의 일관성을 위해 수정이 필요합니다.📝 수정 제안
### Core Framework -- **Spring Boot 3.1.5**: 스프링 부트 +- **Spring Boot 3.5.11**: 스프링 부트 - **Spring Security**: JWT 기반 인증🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@claude.md` at line 170, Update the outdated Spring Boot version text "Spring Boot 3.1.5" in the "기술 스택 상세" section to match the document's updated version "Spring Boot 3.5.11" (as referenced earlier in the doc), ensuring all occurrences of "Spring Boot 3.1.5" are replaced and the version string is consistent throughout the file.
🧹 Nitpick comments (2)
src/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.java (1)
94-101: JJWT 0.12.6 마이그레이션에 따른 테스트 코드의 deprecated API 사용 확인프로덕션 코드에서 JJWT 0.12.6의 새 API로 이미 마이그레이션이 완료되었으나, 테스트 코드에서는 deprecated API가 여전히 사용 중입니다. 이 파일의
createTokenWithExpiration메서드에서 다음과 같은 개선이 필요합니다:
Claim 설정 메서드 변경
setSubject()→subject()setIssuedAt()→issuedAt()setExpiration()→expiration()서명 방식 업데이트
signWith(SignatureAlgorithm.HS256, secret)→signWith(key, Jwts.SIG.HS256)형태로 변경하여 SecretKey 객체 사용 필요♻️ 적용 예시
+import io.jsonwebtoken.security.Keys; +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; private String createTokenWithExpiration(Date expiration) { + SecretKey key = Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(StandardCharsets.UTF_8)); return Jwts.builder() - .setSubject("1") - .setIssuedAt(new Date()) - .setExpiration(expiration) - .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) + .subject("1") + .issuedAt(new Date()) + .expiration(expiration) + .signWith(key, Jwts.SIG.HS256) .compact(); }참고: 유사한 deprecated API 사용이
SignOutCheckFilterTest.java,TokenAuthenticationProviderTest.java에도 있으니 함께 검토하길 권장합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.java` around lines 94 - 101, The test method createTokenWithExpiration uses deprecated JJWT APIs; update it to use the new builder methods and a SecretKey: replace setSubject/setIssuedAt/setExpiration with subject()/issuedAt()/expiration(), and replace signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) by creating a SecretKey (e.g., Keys.hmacShaKeyFor(jwtProperties.secret().getBytes())) and calling signWith(secretKey, Jwts.SIG.HS256); update the Jwts.builder() call accordingly in createTokenWithExpiration and apply the same pattern to SignOutCheckFilterTest and TokenAuthenticationProviderTest.src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java (1)
48-50:Keys.hmacShaKeyFor()사용에 대한 참고 사항
Keys.hmacShaKeyFor()는 키 길이에 따라 HMAC 알고리즘을 자동으로 선택합니다:
- 32+ 바이트 → HS256
- 48+ 바이트 → HS384
- 64+ 바이트 → HS512
현재 설정된 JWT 시크릿이 최소 32바이트 이상인지 확인해주세요. 테스트 환경의 시크릿
"1234567-1234-1234-1234-12345678901"은 34바이트로 HS256이 적용됩니다.💡 보안 강화를 위한 권장 사항 (선택적)
프로덕션 환경에서는 더 긴 시크릿 키(64+ 바이트)를 사용하여 HS512 알고리즘을 적용하는 것을 권장합니다. 이는 현재 기능에 영향을 주지 않으며 향후 보안 강화를 위한 제안입니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java` around lines 48 - 50, The getSigningKey() method uses Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(...)) which selects HS256/384/512 based on secret length; ensure jwtProperties.secret() is at least 32 bytes (preferably 64+ for HS512 in production) by validating its byte length in JwtTokenProvider (e.g., in getSigningKey() or during JwtTokenProvider initialization) and throw a clear exception or log an error if the secret is too short so the application fails fast instead of producing a weaker-than-expected algorithm; reference getSigningKey(), Keys.hmacShaKeyFor, and jwtProperties.secret() when adding the validation or documentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@build.gradle`:
- Around line 46-48: Three test files still use the old JJWT builder/signing API
and must be updated to the 0.12.6 API: in TokenAuthenticationProviderTest,
TokenAuthenticationFilterTest, and SignOutCheckFilterTest replace uses of
signWith(SignatureAlgorithm.HS256, key) with signWith(secretKey) (ensure the
test creates a SecretKey instance as used in production), and rename JWT builder
setters setSubject(...), setIssuedAt(...), setExpiration(...) to the new fluent
names subject(...), issuedAt(...), expiration(...); update imports/usages
accordingly so the tests compile against the jjwt-api 0.12.6 methods.
---
Outside diff comments:
In `@claude.md`:
- Line 170: Update the outdated Spring Boot version text "Spring Boot 3.1.5" in
the "기술 스택 상세" section to match the document's updated version "Spring Boot
3.5.11" (as referenced earlier in the doc), ensuring all occurrences of "Spring
Boot 3.1.5" are replaced and the version string is consistent throughout the
file.
---
Nitpick comments:
In `@src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java`:
- Around line 48-50: The getSigningKey() method uses
Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(...)) which selects
HS256/384/512 based on secret length; ensure jwtProperties.secret() is at least
32 bytes (preferably 64+ for HS512 in production) by validating its byte length
in JwtTokenProvider (e.g., in getSigningKey() or during JwtTokenProvider
initialization) and throw a clear exception or log an error if the secret is too
short so the application fails fast instead of producing a weaker-than-expected
algorithm; reference getSigningKey(), Keys.hmacShaKeyFor, and
jwtProperties.secret() when adding the validation or documentation.
In
`@src/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.java`:
- Around line 94-101: The test method createTokenWithExpiration uses deprecated
JJWT APIs; update it to use the new builder methods and a SecretKey: replace
setSubject/setIssuedAt/setExpiration with subject()/issuedAt()/expiration(), and
replace signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) by creating a
SecretKey (e.g., Keys.hmacShaKeyFor(jwtProperties.secret().getBytes())) and
calling signWith(secretKey, Jwts.SIG.HS256); update the Jwts.builder() call
accordingly in createTokenWithExpiration and apply the same pattern to
SignOutCheckFilterTest and TokenAuthenticationProviderTest.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5ad9c635-8f52-4383-b53a-b009b66270bf
📒 Files selected for processing (22)
.github/workflows/ci.yml.github/workflows/dev-cd.yml.github/workflows/prod-cd.ymlDockerfilebuild.gradleclaude.mdsrc/main/java/com/example/solidconnection/auth/client/AppleOAuthClient.javasrc/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.javasrc/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.javasrc/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.javasrc/test/java/com/example/solidconnection/auth/controller/RefreshTokenCookieManagerTest.javasrc/test/java/com/example/solidconnection/auth/service/JwtTokenProviderTest.javasrc/test/java/com/example/solidconnection/auth/service/oauth/OAuthServiceTest.javasrc/test/java/com/example/solidconnection/auth/service/signup/SignUpTokenProviderTest.javasrc/test/java/com/example/solidconnection/chat/service/ChatServiceTest.javasrc/test/java/com/example/solidconnection/community/post/service/PostCommandServiceTest.javasrc/test/java/com/example/solidconnection/mentor/service/MentorApplicationServiceTest.javasrc/test/java/com/example/solidconnection/news/service/NewsCommandServiceTest.javasrc/test/java/com/example/solidconnection/score/service/ScoreServiceTest.javasrc/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.javasrc/test/java/com/example/solidconnection/siteuser/service/MyPageServiceTest.javasrc/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java
| implementation 'io.jsonwebtoken:jjwt-api:0.12.6' | ||
| runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6' | ||
| runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6' |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 이전 JJWT API를 사용하는 파일 검색
echo "=== SignatureAlgorithm 사용 파일 ==="
rg -n "SignatureAlgorithm" --type java
echo ""
echo "=== setSubject/setIssuedAt/setExpiration 사용 파일 ==="
rg -n "setSubject|setIssuedAt|setExpiration" --type java -g '!build/**'Repository: solid-connection/solid-connect-server
Length of output: 3760
🏁 Script executed:
# Verify the actual migration path for JJWT 0.12.6 API
rg -A 2 "signWith\(" src/test/java/com/example/solidconnection/security/ --type java | head -20Repository: solid-connection/solid-connect-server
Length of output: 2106
JJWT 0.12.6 마이그레이션이 세 개의 테스트 파일에서 미완료되었습니다.
build.gradle 의존성 업그레이드는 올바르게 수행되었으나, 다음 세 개의 테스트 파일이 여전히 이전 JJWT API를 사용하고 있어 컴파일 오류가 발생할 것입니다:
src/test/java/com/example/solidconnection/security/authentication/TokenAuthenticationProviderTest.javasrc/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.javasrc/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java
각 파일마다 다음과 같은 API 변경이 필요합니다:
- `signWith(SignatureAlgorithm.HS256, key)` → `signWith(secretKey)`
- `setSubject()` → `subject()`
- `setIssuedAt()` → `issuedAt()`
- `setExpiration()` → `expiration()`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@build.gradle` around lines 46 - 48, Three test files still use the old JJWT
builder/signing API and must be updated to the 0.12.6 API: in
TokenAuthenticationProviderTest, TokenAuthenticationFilterTest, and
SignOutCheckFilterTest replace uses of signWith(SignatureAlgorithm.HS256, key)
with signWith(secretKey) (ensure the test creates a SecretKey instance as used
in production), and rename JWT builder setters setSubject(...),
setIssuedAt(...), setExpiration(...) to the new fluent names subject(...),
issuedAt(...), expiration(...); update imports/usages accordingly so the tests
compile against the jjwt-api 0.12.6 methods.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/test/java/com/example/solidconnection/security/authentication/TokenAuthenticationProviderTest.java`:
- Line 121: 테스트의 토큰 만료 시간이 너무 짧아 간헐적 실패를 유발하므로 TokenAuthenticationProviderTest에서
Date(System.currentTimeMillis() + 1000)로 생성한 만료 시간을 늘리세요: expiration(...)에 더 긴
TTL(예: 몇 만 밀리초 또는 Duration/TimeUnit을 사용해 30s~5min 범위)으로 변경하거나 상수(EXPIRATION_MS)로
추출해 안정적인 값으로 설정하고, 필요하면 테스트 전용 고정 Clock/시간 제어를 도입해 토큰 만료 타이밍을 안정화하세요; 변경 대상 식별자:
TokenAuthenticationProviderTest, expiration(...) 호출,
Date(System.currentTimeMillis() + ...).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d6c228ef-fa3b-43a8-9364-6a01490514b6
📒 Files selected for processing (3)
src/test/java/com/example/solidconnection/security/authentication/TokenAuthenticationProviderTest.javasrc/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.javasrc/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.java
✅ Files skipped from review due to trivial changes (1)
- src/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
- src/test/java/com/example/solidconnection/security/filter/TokenAuthenticationFilterTest.java
| .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) | ||
| .subject(String.valueOf(id)) | ||
| .issuedAt(new Date()) | ||
| .expiration(new Date(System.currentTimeMillis() + 1000)) |
There was a problem hiding this comment.
2) 유효 토큰 TTL이 1초라서 테스트가 간헐적으로 깨질 수 있습니다.
Line 121의 + 1000은 통합 테스트 환경에서 너무 짧습니다. 인증 처리 지연 시 만료되어, 정상 인증/없는 사용자 케이스가 INVALID_TOKEN으로 바뀌어 CI flaky를 유발할 수 있습니다.
🔧 제안 수정안
class TokenAuthenticationProviderTest {
+ private static final long VALID_TOKEN_TTL_MS = 5 * 60 * 1000L;
+
@@
private String createValidToken(long id) {
return Jwts.builder()
.subject(String.valueOf(id))
.issuedAt(new Date())
- .expiration(new Date(System.currentTimeMillis() + 1000))
+ .expiration(new Date(System.currentTimeMillis() + VALID_TOKEN_TTL_MS))
.signWith(Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(StandardCharsets.UTF_8)))
.compact();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .expiration(new Date(System.currentTimeMillis() + 1000)) | |
| private String createValidToken(long id) { | |
| return Jwts.builder() | |
| .subject(String.valueOf(id)) | |
| .issuedAt(new Date()) | |
| .expiration(new Date(System.currentTimeMillis() + VALID_TOKEN_TTL_MS)) | |
| .signWith(Keys.hmacShaKeyFor(jwtProperties.secret().getBytes(StandardCharsets.UTF_8))) | |
| .compact(); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/test/java/com/example/solidconnection/security/authentication/TokenAuthenticationProviderTest.java`
at line 121, 테스트의 토큰 만료 시간이 너무 짧아 간헐적 실패를 유발하므로
TokenAuthenticationProviderTest에서 Date(System.currentTimeMillis() + 1000)로 생성한
만료 시간을 늘리세요: expiration(...)에 더 긴 TTL(예: 몇 만 밀리초 또는 Duration/TimeUnit을 사용해
30s~5min 범위)으로 변경하거나 상수(EXPIRATION_MS)로 추출해 안정적인 값으로 설정하고, 필요하면 테스트 전용 고정
Clock/시간 제어를 도입해 토큰 만료 타이밍을 안정화하세요; 변경 대상 식별자: TokenAuthenticationProviderTest,
expiration(...) 호출, Date(System.currentTimeMillis() + ...).
관련 이슈
작업 내용
버전 업그레이드
❯ - Java 17 → 21
JJWT 라이브러리 교체
❯ -
jjwt:0.9.1(단일 jar) →jjwt-api/impl/jackson:0.12.6(모듈 분리)javax.xml.bind:jaxb-api의존성 제거 (jjwt 0.9.x 전용 workaround)SignatureAlgorithm→Jwts.SIG.ES256/Keys.hmacShaKeyFor()setSigningKey/parseClaimsJws/getBody→verifyWith/parseSignedClaims/getPayloadJwts.claims().setSubject()→ 빌더 체이닝 방식org.apache.tomcat.Base64→java.util.Base64(표준 라이브러리)의존성 추가
❯ -
commons-lang3추가CI/CD 및 인프라
❯ - GitHub Actions (ci.yml, dev-cd.yml, prod-cd.yml): JDK 17 → 21
eclipse-temurin:17-jdk→eclipse-temurin:21-jdk특이 사항
리뷰 요구사항 (선택)