[BE] [REFACTOR] JWT 클래스 유지보수성 향상 - JwtUtils 단일화 및 클레임 키 상수화#252
Hidden character warning
[BE] [REFACTOR] JWT 클래스 유지보수성 향상 - JwtUtils 단일화 및 클레임 키 상수화#252discipline24 merged 4 commits intomainfrom
Conversation
WalkthroughJwtProvider를 제거하고 JwtParser를 JwtUtils로 대체하여 토큰 생성·검증·추출 및 리프레시 암호화 기능을 JwtUtils로 통합했으며, 관련 서비스·필터·테스트들의 의존성을 JwtUtils로 교체했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant RefreshAPI as RefreshEndpoint
participant RefreshSvc as RefreshTokenService
participant TokenEnc as TokenEncryptor
participant JwtUtils as JwtUtils
participant UserRepo as UserRepository
Client->>RefreshAPI: POST /auth/refresh (refreshToken)
RefreshAPI->>RefreshSvc: validateAndRefresh(refreshToken)
RefreshSvc->>TokenEnc: decrypt(refreshToken)
TokenEnc-->>RefreshSvc: rawRefreshToken
RefreshSvc->>JwtUtils: getUserIdFromToken(rawRefreshToken)
JwtUtils-->>RefreshSvc: userId
RefreshSvc->>UserRepo: findActiveUser(userId)
UserRepo-->>RefreshSvc: User
RefreshSvc->>JwtUtils: createToken(userId, role, email)
JwtUtils-->>RefreshSvc: accessToken
RefreshSvc->>JwtUtils: createRefreshToken(userId)
JwtUtils-->>TokenEnc: (returns encrypted refresh token)
JwtUtils-->>RefreshSvc: refreshToken
RefreshSvc-->>RefreshAPI: tokens
RefreshAPI-->>Client: 200 { accessToken, refreshToken }
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
backend/src/test/java/org/sejongisc/backend/backtest/controller/TemplateControllerTest.java (1)
85-87: JWT 인증 목 스텁은 헬퍼 메서드로 추출해도 좋겠습니다.동일 stubbing 반복이 많아, 헬퍼로 묶으면 테스트 가독성과 변경 내성이 좋아집니다.
리팩터 예시
+ private void stubAuthenticated(UUID uid) { + when(jwtUtils.validationToken(TOKEN)).thenReturn(true); + when(jwtUtils.getAuthentication(TOKEN)).thenReturn(인증토큰(uid)); + } ... - when(jwtUtils.validationToken(TOKEN)).thenReturn(true); - when(jwtUtils.getAuthentication(TOKEN)).thenReturn(인증토큰(uid)); + stubAuthenticated(uid);Also applies to: 104-106, 121-123, 152-154, 176-178
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/test/java/org/sejongisc/backend/backtest/controller/TemplateControllerTest.java` around lines 85 - 87, Extract a reusable helper in TemplateControllerTest that encapsulates the repeated JWT stubbing: create a private method (e.g., mockJwtFor(String token, Long uid)) that performs when(jwtUtils.validationToken(token)).thenReturn(true) and when(jwtUtils.getAuthentication(token)).thenReturn(인증토큰(uid)), then replace the duplicated stubbing blocks (the occurrences around lines shown) with calls to mockJwtFor(TOKEN, uid) to improve readability and maintainability.backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java (2)
78-99: 테스트 설정 개선 제안.현재
@InjectMocks로 선언된authController가setUp()에서 수동으로 다시 생성되어 mock 주입이 무시됩니다.@InjectMocks를 제거하거나, 수동 생성을 제거하고 Mockito의 자동 주입을 활용하는 것이 명확합니다.♻️ 개선 제안
옵션 1:
@InjectMocks제거 (현재 수동 생성 유지 시)- `@InjectMocks` - AuthController authController; + AuthController authController;옵션 2: 수동 생성 제거 (Mockito 자동 주입 활용 시)
setUp()에서authController = new AuthController(...)라인을 제거하고@InjectMocks가 자동으로 mock을 주입하도록 합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java` around lines 78 - 99, The test currently re-creates authController inside setUp(), which overrides any `@InjectMocks-driven` Mockito injection; remove the manual instantiation line authController = new AuthController(authService, refreshTokenService, authCookieHelper) so Mockito can inject the mocks into the `@InjectMocks` authController, and ensure mocks are initialized (e.g., annotate the test class with `@ExtendWith`(MockitoExtension.class) or call MockitoAnnotations.openMocks(this) in a `@BeforeEach`) to enable automatic injection.
192-194: OAuth 테스트의 stub 유효성 확인 필요.
jwtUtils.createToken()및createRefreshToken()stub이 설정되어 있지만,AuthController가@InjectMocks가 아닌 수동 생성(Line 86)으로 초기화되므로 이 mock이 실제로 주입되지 않을 수 있습니다. 테스트가 현재 통과한다면, 실제 토큰 생성 로직이 다른 서비스(예:AuthService)에서 처리되고 있을 가능성이 있습니다.이 경우 해당 stub 코드는 제거하거나, 실제 토큰 생성이 일어나는 서비스의 mock을 통해 stubbing해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java` around lines 192 - 194, The jwtUtils.createToken/createRefreshToken stubs are ineffective because AuthController is constructed manually (not via `@InjectMocks`), so jwtUtils won’t be injected; either remove these jwtUtils stubs or update the test to stub the actual component that produces tokens (e.g., mock AuthService and stub AuthService.createToken()/createRefreshToken() or change test to use `@InjectMocks` for AuthController so jwtUtils is injected) — locate references to jwtUtils.createToken, jwtUtils.createRefreshToken, AuthController construction, and AuthService in the test and apply one of these fixes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtUtils.java`:
- Around line 134-140: Wrap the call to
customUserDetailsService.loadUserByUsername(userId) in a try/catch and normalize
any thrown runtime exceptions into a JwtException (or rethrow JwtException) so
JWT filter sees a JWT-related error (returning 401) instead of allowing a 500;
also ensure you validate userId (null/blank check) before calling
loadUserByUsername and include the original exception message as context when
creating the JwtException. Target the block around
customUserDetailsService.loadUserByUsername(userId) in JwtUtils (the userId null
check and the subsequent loadUserByUsername call).
In
`@backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java`:
- Line 66: Remove the unused JwtUtils mock and all its stubbing in the test:
delete the field declaration "@Mock JwtUtils jwtUtils" and remove any when(...)
/ doReturn(...) stubbing that references jwtUtils in AuthControllerTest (these
stubs are not injected into AuthController which is constructed in
setUp(authService, refreshTokenService, authCookieHelper)); also remove any
now-unused imports or helper references related to JwtUtils.
---
Nitpick comments:
In
`@backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java`:
- Around line 78-99: The test currently re-creates authController inside
setUp(), which overrides any `@InjectMocks-driven` Mockito injection; remove the
manual instantiation line authController = new AuthController(authService,
refreshTokenService, authCookieHelper) so Mockito can inject the mocks into the
`@InjectMocks` authController, and ensure mocks are initialized (e.g., annotate
the test class with `@ExtendWith`(MockitoExtension.class) or call
MockitoAnnotations.openMocks(this) in a `@BeforeEach`) to enable automatic
injection.
- Around line 192-194: The jwtUtils.createToken/createRefreshToken stubs are
ineffective because AuthController is constructed manually (not via
`@InjectMocks`), so jwtUtils won’t be injected; either remove these jwtUtils stubs
or update the test to stub the actual component that produces tokens (e.g., mock
AuthService and stub AuthService.createToken()/createRefreshToken() or change
test to use `@InjectMocks` for AuthController so jwtUtils is injected) — locate
references to jwtUtils.createToken, jwtUtils.createRefreshToken, AuthController
construction, and AuthService in the test and apply one of these fixes.
In
`@backend/src/test/java/org/sejongisc/backend/backtest/controller/TemplateControllerTest.java`:
- Around line 85-87: Extract a reusable helper in TemplateControllerTest that
encapsulates the repeated JWT stubbing: create a private method (e.g.,
mockJwtFor(String token, Long uid)) that performs
when(jwtUtils.validationToken(token)).thenReturn(true) and
when(jwtUtils.getAuthentication(token)).thenReturn(인증토큰(uid)), then replace the
duplicated stubbing blocks (the occurrences around lines shown) with calls to
mockJwtFor(TOKEN, uid) to improve readability and maintainability.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
backend/src/main/java/org/sejongisc/backend/common/auth/filter/JwtAuthenticationFilter.javabackend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtProvider.javabackend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtUtils.javabackend/src/main/java/org/sejongisc/backend/common/auth/jwt/TokenEncryptor.javabackend/src/main/java/org/sejongisc/backend/common/auth/service/AuthService.javabackend/src/main/java/org/sejongisc/backend/common/auth/service/RefreshTokenService.javabackend/src/test/java/org/sejongisc/backend/attendance/controller/AttendanceRoundControllerTest.javabackend/src/test/java/org/sejongisc/backend/attendance/controller/TestSecurityConfig.javabackend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.javabackend/src/test/java/org/sejongisc/backend/auth/service/AuthServiceTest.javabackend/src/test/java/org/sejongisc/backend/auth/service/RefreshTokenServiceTest.javabackend/src/test/java/org/sejongisc/backend/backtest/controller/TemplateControllerTest.java
💤 Files with no reviewable changes (2)
- backend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtProvider.java
- backend/src/main/java/org/sejongisc/backend/common/auth/jwt/TokenEncryptor.java
backend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtUtils.java
Show resolved
Hide resolved
| AuthService authService; | ||
| @Mock UserService userService; | ||
| @Mock JwtProvider jwtProvider; | ||
| @Mock JwtUtils jwtUtils; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find AuthController class definition and check for JwtUtils dependency
find . -type f -name "AuthController.java" | head -5Repository: SISC-IT/sisc-web
Length of output: 148
🏁 Script executed:
# Search for AuthController class definition and constructor
rg -n "class AuthController" -A 50 --type java | grep -E "(class AuthController|JwtUtils|public AuthController|private.*JwtUtils)" | head -30Repository: SISC-IT/sisc-web
Length of output: 409
🏁 Script executed:
# Check the exact setUp method in the test file
rg -n "void setUp\|AuthController.*new" backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java -A 3 -B 1Repository: SISC-IT/sisc-web
Length of output: 42
🏁 Script executed:
# Check if jwtUtils is used anywhere in the test file
rg -n "jwtUtils\." backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java | head -20Repository: SISC-IT/sisc-web
Length of output: 575
🏁 Script executed:
# Read AuthController class definition to see constructor parameters
cat -n backend/src/main/java/org/sejongisc/backend/common/auth/controller/AuthController.java | head -60Repository: SISC-IT/sisc-web
Length of output: 3319
🏁 Script executed:
# Read the test file setUp method and AuthController instantiation
sed -n '75,95p' backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.javaRepository: SISC-IT/sisc-web
Length of output: 844
🏁 Script executed:
# Check the test methods containing jwtUtils stubbing to see if they use it
sed -n '180,210p' backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.javaRepository: SISC-IT/sisc-web
Length of output: 1467
🏁 Script executed:
# Check other test methods with jwtUtils stubbing
sed -n '340,365p' backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.javaRepository: SISC-IT/sisc-web
Length of output: 1237
🏁 Script executed:
# Check if jwtUtils is referenced anywhere else besides stubbing
rg -n "jwtUtils" backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.javaRepository: SISC-IT/sisc-web
Length of output: 607
사용되지 않는 mock 필드 제거 필요.
AuthController 클래스는 JwtUtils를 의존성으로 가지지 않으며, 테스트의 setUp() 메서드(라인 86)에서 AuthController를 (authService, refreshTokenService, authCookieHelper)만으로 생성합니다. jwtUtils mock은 선언되고 라인 192, 194, 355, 356, 378, 379에서 stubbing되지만 실제로 주입되지 않아 사용되지 않는 코드입니다. 이 mock 필드와 모든 관련 stubbing 문들을 제거하세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@backend/src/test/java/org/sejongisc/backend/auth/controller/AuthControllerTest.java`
at line 66, Remove the unused JwtUtils mock and all its stubbing in the test:
delete the field declaration "@Mock JwtUtils jwtUtils" and remove any when(...)
/ doReturn(...) stubbing that references jwtUtils in AuthControllerTest (these
stubs are not injected into AuthController which is constructed in
setUp(authService, refreshTokenService, authCookieHelper)); also remove any
now-unused imports or helper references related to JwtUtils.
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
`@backend/src/main/java/org/sejongisc/backend/common/auth/service/AuthService.java`:
- Around line 31-35: Remove the unused JwtParser field from AuthService to fix
the compilation error: delete the declaration "private final JwtParser
jwtParser;" (and any related unused imports) since all JWT operations in
AuthService use jwtUtils (look at usages around jwtUtils at lines where tokens
are parsed/validated). Keep the other fields (jwtUtils, RefreshTokenRepository,
ApplicationEventPublisher) and let `@RequiredArgsConstructor` generate the correct
constructor without JwtParser.
backend/src/main/java/org/sejongisc/backend/common/auth/service/AuthService.java
Show resolved
Hide resolved
backend/src/main/java/org/sejongisc/backend/common/auth/jwt/JwtUtils.java
Show resolved
Hide resolved
| throw new CustomException(ErrorCode.UNAUTHORIZED); | ||
| } | ||
|
|
||
| String accessToken = jwtUtils.createToken(user.getUserId(), user.getRole(), user.getEmail()); |
There was a problem hiding this comment.
이부분은 PENDING_MEMBER 검증 이전으로 올린 이유가 궁금합니다!
There was a problem hiding this comment.
음 그 부분은 제가 반영되기 전 코드에서 작업한 것 같아서 수정해야 할 것 같습니당
Summary
JwtParser,JwtProvider두 클래스를JwtUtils로 단일화"uid","role") 상수화로 하드코딩 제거@PostConstruct init(),SecretKey초기화,validationToken()등 중복 코드 제거getUserIdFromToken()반환 타입을UUID로 통일TokenEncryptor의 불필요한@Configuration어노테이션 제거JwtUtils적용 및RefreshTokenServiceTestTokenEncryptor목 누락 버그 수정Test plan
Summary by CodeRabbit