[Feat] JWT 인증 필터 구현 - #15
Conversation
📝 WalkthroughWalkthrough
ChangesJWT 인증 필터 구현
Sequence Diagram(s)sequenceDiagram
participant Client as 클라이언트
participant JwtAuthFilter as JwtAuthenticationFilter
participant JwtProvider
participant SecurityContext as SecurityContextHolder
participant NextFilter as 다음 필터/컨트롤러
Client->>JwtAuthFilter: HTTP 요청 (Authorization: Bearer <token>)
JwtAuthFilter->>JwtAuthFilter: resolveToken() — Bearer 토큰 추출
alt 토큰 존재
JwtAuthFilter->>JwtProvider: validateToken(token)
alt 유효한 토큰
JwtProvider-->>JwtAuthFilter: true
JwtAuthFilter->>JwtProvider: getAuthentication(token)
JwtProvider->>JwtProvider: getUserId(token), getRole(token)
JwtProvider-->>JwtAuthFilter: UsernamePasswordAuthenticationToken
JwtAuthFilter->>SecurityContext: setAuthentication(authToken)
JwtAuthFilter->>NextFilter: filterChain.doFilter()
else 만료/무효 토큰
JwtProvider-->>JwtAuthFilter: CustomException (EXPIRED_TOKEN / INVALID_TOKEN)
JwtAuthFilter->>SecurityContext: clearContext()
JwtAuthFilter-->>Client: 401 Unauthorized (JSON)
end
else 토큰 없음
JwtAuthFilter->>NextFilter: filterChain.doFilter()
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 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)
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)
src/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java (2)
14-14: 🧹 Nitpick | 🔵 Trivial | 💤 Low value사용되지 않는 import 제거 필요.
User클래스가 import되었지만 코드에서 사용되지 않습니다.-import org.springframework.security.core.userdetails.User;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java` at line 14, Remove the unused import statement for the User class from org.springframework.security.core.userdetails in the JwtProvider class. Search through the entire JwtProvider.java file to verify that the User class is not referenced anywhere in the code, then delete the import line.
63-75: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
validateToken메서드 시그니처가 실제 동작과 불일치.메서드가
boolean을 반환하지만, 검증 실패 시 항상 예외를 던지므로false를 반환하는 경우가 없습니다. 이로 인해 호출자가 반환값을 검사하는 대신 예외를 catch해야 합니다.반환 타입을
void로 변경하거나, 예외를 던지지 않고false를 반환하는 방식 중 하나를 선택하세요.♻️ 옵션 1: void 반환으로 변경
- public boolean validateToken(String token) { + public void validateToken(String token) { try { getClaims(token); - return true; } catch (ExpiredJwtException e) { log.warn("[JWT] 만료된 토큰: {}", e.getMessage()); throw new CustomException(ErrorCode.EXPIRED_TOKEN); } catch (Exception e) { log.warn("[JWT] 유효하지 않은 토큰: {}", e.getMessage()); - throw new CustomException(ErrorCode.INVALID_TOKEN); + throw new CustomException(ErrorCode.INVALID_TOKEN); } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java` around lines 63 - 75, The validateToken method in JwtProvider class has a return type of boolean but never returns false; it either returns true or throws an exception. This makes the boolean return type misleading since callers cannot rely on a false return value for validation failures. Change the return type from boolean to void since the method uses exceptions for error handling (throwing CustomException with EXPIRED_TOKEN or INVALID_TOKEN error codes) to make the method contract match its actual behavior.src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java (1)
35-38: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win토큰이 두 번 파싱됨 - 비효율적.
validateToken과getAuthentication모두 내부적으로getClaims를 호출하여 토큰을 파싱합니다. 매 요청마다 동일한 토큰을 두 번 파싱하는 것은 불필요한 오버헤드입니다.
getAuthentication호출만으로 검증과 인증 객체 생성을 동시에 처리하거나,JwtProvider에서 파싱 결과를 재사용하는 방식을 고려하세요.♻️ 제안: validateToken 호출 제거
if (StringUtils.hasText(token)) { try { - jwtProvider.validateToken(token); Authentication authentication = jwtProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); log.debug("[JWT] 인증 성공 userId = {}", authentication.getName()); } catch (Exception e) {
getAuthentication내부에서getClaims가 호출되므로, 토큰이 유효하지 않으면 예외가 발생합니다. 단, 예외 타입 구분이 필요하다면getAuthentication에서 예외 처리를 추가해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java` around lines 35 - 38, The token is being parsed twice in the doFilterInternal method of JwtAuthenticationFilter - once by validateToken and once by getAuthentication, both of which call getClaims internally. Remove the redundant jwtProvider.validateToken(token) call and rely only on the jwtProvider.getAuthentication(token) method, which will automatically throw an exception if the token is invalid during the Claims parsing. If exception type distinction is required for handling different validation failures, add appropriate exception handling logic within the getAuthentication method or the surrounding try-catch block to differentiate between validation errors and other failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java`:
- Around line 61-68: The sendUnauthorizedResponse method uses manual string
replacement to escape only double quotes when building the JSON response, which
does not handle other special characters like backslashes, newlines, and tabs
that require escaping in JSON. This can produce invalid JSON if the message
parameter contains these characters. Replace the manual JSON string construction
with Jackson's ObjectMapper to safely serialize the error response object as
JSON, which will automatically handle all necessary character escaping and
ensure valid JSON output.
In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java`:
- Around line 82-85: The getRole method in JwtProvider attempts to extract the
"role" claim from tokens without checking if the claim exists, causing a
NullPointerException when called with refresh tokens since they do not contain a
"role" claim. Add token type validation before calling getRole to ensure it is
only invoked with access tokens that contain the role claim. Alternatively, add
null checking in the getRole method to handle cases where the "role" claim is
absent, either by returning a default role value or throwing a more descriptive
exception that clarifies the token type issue.
---
Nitpick comments:
In
`@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java`:
- Around line 35-38: The token is being parsed twice in the doFilterInternal
method of JwtAuthenticationFilter - once by validateToken and once by
getAuthentication, both of which call getClaims internally. Remove the redundant
jwtProvider.validateToken(token) call and rely only on the
jwtProvider.getAuthentication(token) method, which will automatically throw an
exception if the token is invalid during the Claims parsing. If exception type
distinction is required for handling different validation failures, add
appropriate exception handling logic within the getAuthentication method or the
surrounding try-catch block to differentiate between validation errors and other
failures.
In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java`:
- Line 14: Remove the unused import statement for the User class from
org.springframework.security.core.userdetails in the JwtProvider class. Search
through the entire JwtProvider.java file to verify that the User class is not
referenced anywhere in the code, then delete the import line.
- Around line 63-75: The validateToken method in JwtProvider class has a return
type of boolean but never returns false; it either returns true or throws an
exception. This makes the boolean return type misleading since callers cannot
rely on a false return value for validation failures. Change the return type
from boolean to void since the method uses exceptions for error handling
(throwing CustomException with EXPIRED_TOKEN or INVALID_TOKEN error codes) to
make the method contract match its actual behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4bead06d-1ffb-418f-ac0f-7f524ea0efed
📒 Files selected for processing (4)
src/main/java/com/ilson/spotwork/infra/security/SecurityConfig.javasrc/main/java/com/ilson/spotwork/infra/security/jwt/CustomUserDetails.javasrc/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.javasrc/main/java/com/ilson/spotwork/infra/security/jwt/JwtProvider.java
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java (1)
43-48: 🩺 Stability & Availability | 🟠 Major
e.getMessage()가 null이면Map.of가 NullPointerException을 던져 401 응답이 전달되지 않습니다.두 가지 문제가 있습니다.
e.getMessage()는 일부 예외(예:NullPointerException,ClassCastException등)에서null을 반환합니다.java.util.Map.of(...)는 null 값을 허용하지 않으므로 line 69의Map.of("code", 401, "message", message)호출에서NullPointerException이 발생하고, 이 NPE가 catch 블록 밖으로 전파되어 401 응답 대신 500 오류가 발생합니다.- 예외 메시지를 그대로 응답 바디에 담으면 토큰 검증 관련 내부 정보가 클라이언트에 노출됩니다. 일반화된 메시지를 반환하는 것이 안전합니다.
호출 지점에서 고정 메시지를 전달하면 두 문제가 모두 해소됩니다(상세 사유는 로그에만 유지).
🛡️ 제안 수정
} catch (Exception e) { log.warn("[JWT] 인증 실패: {}", e.getMessage()); SecurityContextHolder.clearContext(); - sendUnauthorizedResponse(response, e.getMessage()); + sendUnauthorizedResponse(response, "인증에 실패했습니다."); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java` around lines 43 - 48, In the exception catch block within JwtAuthenticationFilter, the `sendUnauthorizedResponse(response, e.getMessage())` call at line 47 passes the raw exception message, which can be null for certain exceptions like NullPointerException, causing a NullPointerException in Map.of and exposing internal details to clients. Replace the call to sendUnauthorizedResponse to pass a fixed generic error message (e.g., "인증 실패") instead of e.getMessage(), while keeping the detailed error message in the log.warn statement for debugging purposes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java`:
- Around line 43-48: In the exception catch block within
JwtAuthenticationFilter, the `sendUnauthorizedResponse(response,
e.getMessage())` call at line 47 passes the raw exception message, which can be
null for certain exceptions like NullPointerException, causing a
NullPointerException in Map.of and exposing internal details to clients. Replace
the call to sendUnauthorizedResponse to pass a fixed generic error message
(e.g., "인증 실패") instead of e.getMessage(), while keeping the detailed error
message in the log.warn statement for debugging purposes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 16760f33-a036-4d0c-824d-48098b1b3e39
📒 Files selected for processing (1)
src/main/java/com/ilson/spotwork/infra/security/jwt/JwtAuthenticationFilter.java
관련 이슈
closes #10
구현 내용
주요 구현 포인트
JwtProvider
JwtAuthenticationFilter
CustomUserDetails
체크리스트
Summary by CodeRabbit
릴리스 노트