Conversation
Walkthrough이메일 기반 인증 플로우를 identifier 기반으로 통합하고, 로그아웃 메서드 시그니처를 수정했습니다. 로그인 갱신 시 identifier에서 사용자를 조회하며, CustomUserDetailsService에 EMAIL/KAKAO 타입의 폴백 조회 로직이 추가되었습니다. Changes
예상 코드 리뷰 난이도🎯 2 (Simple) | ⏱️ ~12 분 상세 분석좋은 점 👍
주의 깊게 살펴볼 점
이 정도 규모의 변경은 테스트 케이스도 함께 검토하면 더욱 확실할 것 같습니다! 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. 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: 1
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/finsight/finsight/domain/auth/domain/service/AuthService.java (1)
285-287:⚠️ Potential issue | 🟡 Minor카카오 중복 가입 시 에러 코드를 개선해야 합니다.
Line 286에서
userAuthRepository.existsByIdentifier(kakaoId)로 카카오 ID 중복을 체크하면서AuthErrorCode.DUPLICATE_EMAIL을 던지고 있습니다. 현재DUPLICATE_EMAIL의 메시지는 "이미 존재하는 이메일입니다."인데, 카카오 소셜 로그인 사용자는 자신이 이메일을 입력한 적이 없기 때문에 이 에러 메시지를 받으면 혼란스러울 수 있습니다.권장 해결책:
DUPLICATE_KAKAO_ACCOUNT또는DUPLICATE_KAKAO_ID같은 새로운 에러 코드를 AuthErrorCode에 추가하고, 메시지를 "이미 가입된 카카오 계정입니다." 정도로 설정하는 것이 좋습니다.- 또는 기존 DUPLICATE_EMAIL 사용을 유지하되, 카카오 플로우에서는 더 일반적인 "이미 가입된 계정입니다." 같은 메시지로 변경할 수도 있습니다.
현재는 기능적으로 중복 가입을 방지하지만, 사용자 경험 관점에서 명확히 개선할 필요가 있습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/finsight/finsight/domain/auth/domain/service/AuthService.java` around lines 285 - 287, The duplicate-Kakao check currently throws AuthErrorCode.DUPLICATE_EMAIL which is misleading; add a new enum constant (e.g., DUPLICATE_KAKAO_ACCOUNT or DUPLICATE_KAKAO_ID) to AuthErrorCode with message "이미 가입된 카카오 계정입니다." (or appropriate localized text), then update the duplicate check in AuthService (the existsByIdentifier(kakaoId) branch) to throw the new AuthErrorCode instead of DUPLICATE_EMAIL; ensure any tests or places that map error codes to HTTP responses/logging are updated to handle the new code.
🧹 Nitpick comments (1)
src/main/java/com/finsight/finsight/global/security/CustomUserDetailsService.java (1)
19-23: identifier 기반 폴백 조회 로직, 깔끔하게 잘 구현되었습니다! 👍
Optional.or()를 활용한 EMAIL → KAKAO 폴백 패턴이 읽기 쉽고 명확합니다.다만 한 가지 참고 사항: 동일한 EMAIL → KAKAO 폴백 조회 패턴이
AuthService의refresh(),logout()메서드에서도 반복됩니다. 현재는 3곳에서 중복되고 있어요. 나중에 새로운AuthType이 추가되거나 조회 순서가 변경되면 모든 곳을 동시에 수정해야 합니다.
UserAuthRepository에 다음과 같은 default 메서드를 추가하면 중복을 줄일 수 있습니다:♻️ 중복 제거를 위한 리팩터링 제안
// UserAuthRepository에 추가 default Optional<UserAuthEntity> findByIdentifierWithFallback(String identifier) { return findByIdentifierAndAuthType(identifier, AuthType.EMAIL) .or(() -> findByIdentifierAndAuthType(identifier, AuthType.KAKAO)); }그러면 각 호출처에서:
- .findByIdentifierAndAuthType(identifier, AuthType.EMAIL) - .or(() -> userAuthRepository.findByIdentifierAndAuthType(identifier, AuthType.KAKAO)) + .findByIdentifierWithFallback(identifier)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/finsight/finsight/global/security/CustomUserDetailsService.java` around lines 19 - 23, 중복된 identifier 기반 폴백 조회(EMAIL → KAKAO)가 CustomUserDetailsService.loadUserByUsername, AuthService.refresh, AuthService.logout에 반복되어 유지보수 비용이 생깁니다; UserAuthRepository에 findByIdentifierWithFallback(String identifier) 같은 default 메서드를 추가해 내부에서 findByIdentifierAndAuthType(identifier, AuthType.EMAIL).or(() -> findByIdentifierAndAuthType(identifier, AuthType.KAKAO))로 처리하고, CustomUserDetailsService.loadUserByUsername 및 AuthService.refresh/ logout에서 기존 직접 쿼리 체인을 삭제하고 이 새 repository 메서드 호출로 대체하세요 so that lookup logic is centralized and future AuthType/order changes require one edit.
🤖 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/main/java/com/finsight/finsight/domain/auth/domain/service/AuthService.java`:
- Around line 198-222: Rename JwtUtil.getEmail(...) to getIdentifier(...) and
rename its parameter from email to identifier (and similarly rename any local
variables called email to identifier) and update
JwtUtil.createAccessToken/createRefreshToken parameter names to accept an
identifier; then update all call sites to use the new names: in AuthService
replace jwtUtil.getEmail(refreshToken) with jwtUtil.getIdentifier(refreshToken)
and use variable identifier for subsequent
jwtUtil.createAccessToken(identifier)/createRefreshToken(identifier); in
JwtFilter replace String email = jwtUtil.getEmail(token) with String identifier
= jwtUtil.getIdentifier(token); keep
CustomUserDetailsService.loadUserByUsername(String identifier) as-is to preserve
behavior.
---
Outside diff comments:
In
`@src/main/java/com/finsight/finsight/domain/auth/domain/service/AuthService.java`:
- Around line 285-287: The duplicate-Kakao check currently throws
AuthErrorCode.DUPLICATE_EMAIL which is misleading; add a new enum constant
(e.g., DUPLICATE_KAKAO_ACCOUNT or DUPLICATE_KAKAO_ID) to AuthErrorCode with
message "이미 가입된 카카오 계정입니다." (or appropriate localized text), then update the
duplicate check in AuthService (the existsByIdentifier(kakaoId) branch) to throw
the new AuthErrorCode instead of DUPLICATE_EMAIL; ensure any tests or places
that map error codes to HTTP responses/logging are updated to handle the new
code.
---
Nitpick comments:
In
`@src/main/java/com/finsight/finsight/global/security/CustomUserDetailsService.java`:
- Around line 19-23: 중복된 identifier 기반 폴백 조회(EMAIL → KAKAO)가
CustomUserDetailsService.loadUserByUsername, AuthService.refresh,
AuthService.logout에 반복되어 유지보수 비용이 생깁니다; UserAuthRepository에
findByIdentifierWithFallback(String identifier) 같은 default 메서드를 추가해 내부에서
findByIdentifierAndAuthType(identifier, AuthType.EMAIL).or(() ->
findByIdentifierAndAuthType(identifier, AuthType.KAKAO))로 처리하고,
CustomUserDetailsService.loadUserByUsername 및 AuthService.refresh/ logout에서 기존
직접 쿼리 체인을 삭제하고 이 새 repository 메서드 호출로 대체하세요 so that lookup logic is centralized
and future AuthType/order changes require one edit.
| String identifier = jwtUtil.getEmail(refreshToken); | ||
|
|
||
| UserAuthEntity userAuth = userAuthRepository | ||
| .findByIdentifierAndAuthType(email, AuthType.EMAIL) | ||
| .findByIdentifierAndAuthType(identifier, AuthType.EMAIL) | ||
| .or(() -> userAuthRepository.findByIdentifierAndAuthType(identifier, AuthType.KAKAO)) | ||
| .orElseThrow(() -> { | ||
| log.warn("[AUTH] event_type=token_refresh_failed email={} reason=user_not_found", email); | ||
| log.warn("[AUTH] event_type=token_refresh_failed identifier={} reason=user_not_found", identifier); | ||
| return new AuthException(AuthErrorCode.USER_NOT_FOUND); | ||
| }); | ||
|
|
||
| if (!refreshToken.equals(userAuth.getRefreshToken())) { | ||
| log.warn("[AUTH] event_type=token_refresh_failed email={} reason=token_mismatch", email); | ||
| log.warn("[AUTH] event_type=token_refresh_failed identifier={} reason=token_mismatch", identifier); | ||
| throw new AuthException(AuthErrorCode.INVALID_TOKEN); | ||
| } | ||
|
|
||
| String newAccessToken = jwtUtil.createAccessToken(email); | ||
| String newRefreshToken = jwtUtil.createRefreshToken(email); | ||
| String newAccessToken = jwtUtil.createAccessToken(identifier); | ||
| String newRefreshToken = jwtUtil.createRefreshToken(identifier); | ||
|
|
||
| userAuth.updateRefreshToken(newRefreshToken, LocalDateTime.now().plusDays(30)); | ||
|
|
||
| // 출석 체크 | ||
| recordAttendance(userAuth.getUser()); | ||
|
|
||
| log.debug("[AUTH] event_type=token_refresh_success email={}", email); | ||
| log.debug("[AUTH] event_type=token_refresh_success identifier={}", identifier); | ||
| return new TokenResponse(newAccessToken, newRefreshToken); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for getEmail method definition and all usages
echo "=== getEmail 메서드 정의 및 호출처 ==="
rg -n 'getEmail' --type=java -C2
echo ""
echo "=== JwtUtil 클래스 위치 확인 ==="
fd 'JwtUtil.java' -type f
echo ""
echo "=== getEmail 메서드만 정확히 찾기 ==="
rg -n 'public.*getEmail' --type=java -A5Repository: IT-Cotato/12th-FinSight-BE
Length of output: 4693
🏁 Script executed:
#!/bin/bash
echo "=== JwtUtil.java 전체 내용 ==="
cat src/main/java/com/finsight/finsight/global/security/JwtUtil.java
echo ""
echo "=== JwtFilter.java 관련 부분 ==="
cat src/main/java/com/finsight/finsight/global/security/JwtFilter.javaRepository: IT-Cotato/12th-FinSight-BE
Length of output: 5012
🏁 Script executed:
#!/bin/bash
echo "=== CustomUserDetailsService 찾기 및 내용 확인 ==="
fd 'CustomUserDetailsService.java' -type f -exec cat {} \;
echo ""
echo "=== loadUserByUsername 메서드 사용 패턴 ==="
rg -n 'loadUserByUsername' --type java -B2 -A2Repository: IT-Cotato/12th-FinSight-BE
Length of output: 1540
🏁 Script executed:
#!/bin/bash
echo "=== CustomUserDetailsService.java 전체 내용 ==="
cat src/main/java/com/finsight/finsight/global/security/CustomUserDetailsService.javaRepository: IT-Cotato/12th-FinSight-BE
Length of output: 1352
🏁 Script executed:
#!/bin/bash
echo "=== JWT 생성 호출처 모두 찾기 (kakaoId 포함) ==="
rg -n 'createAccessToken|createRefreshToken' src/main/java/com/finsight/finsight/domain/auth -B1 -A1
echo ""
echo "=== logout 메서드에서 getEmail 호출 확인 ==="
rg -n 'logout' src/main/java/com/finsight/finsight/domain/auth/domain/service/AuthService.java -A10 | head -30Repository: IT-Cotato/12th-FinSight-BE
Length of output: 2934
JwtUtil.getEmail()의 메서드 이름과 파라미터명을 getIdentifier()와 identifier로 개선해야 합니다.
좋은 지적입니다! 현재 JWT 생성/추출 로직에서 실제로는 이메일이나 카카오ID 모두 저장하고 있는데, 메서드명과 파라미터명이 email로 고정되어 있어서 혼동을 야기합니다.
구체적인 문제:
createAccessToken(String email)/createRefreshToken(String email)→ 실제로는 email, kakaoId, identifier를 모두 받음 (AuthService 171-172, 213-214, 261-262, 307-308줄)- JWT claim key가
"email"로 고정되어 있지만 kakaoId도 저장됨 getEmail(String token)→ 메서드명이 email을 반환한다고 암시하지만 identifier 반환JwtFilter의String email = jwtUtil.getEmail(token)→ 변수명이 email이지만 identifier 포함
다행히 CustomUserDetailsService.loadUserByUsername(String identifier)가 EMAIL → KAKAO 폴백 패턴으로 처리하고 있어서 기능상 문제는 없습니다. 다만 다음에 코드를 읽을 개발자가 "이게 email인가 identifier인가?" 헷갈릴 수 있어요.
♻️ JwtUtil 리팩토링 제안
- public String createAccessToken(String email) {
+ public String createAccessToken(String identifier) {
Claims claims = Jwts.claims();
- claims.put("email", email);
+ claims.put("email", identifier); // claim key는 유지 (역호환)
- public String createRefreshToken(String email) {
+ public String createRefreshToken(String identifier) {
Claims claims = Jwts.claims();
- claims.put("email", email);
+ claims.put("email", identifier);
- public String getEmail(String token) {
+ public String getIdentifier(String token) {그리고 호출처들:
- AuthService 198줄:
jwtUtil.getIdentifier(refreshToken) - AuthService 213-214줄:
jwtUtil.createAccessToken(identifier)/createRefreshToken(identifier) - JwtFilter 51줄:
String identifier = jwtUtil.getIdentifier(token)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/finsight/finsight/domain/auth/domain/service/AuthService.java`
around lines 198 - 222, Rename JwtUtil.getEmail(...) to getIdentifier(...) and
rename its parameter from email to identifier (and similarly rename any local
variables called email to identifier) and update
JwtUtil.createAccessToken/createRefreshToken parameter names to accept an
identifier; then update all call sites to use the new names: in AuthService
replace jwtUtil.getEmail(refreshToken) with jwtUtil.getIdentifier(refreshToken)
and use variable identifier for subsequent
jwtUtil.createAccessToken(identifier)/createRefreshToken(identifier); in
JwtFilter replace String email = jwtUtil.getEmail(token) with String identifier
= jwtUtil.getIdentifier(token); keep
CustomUserDetailsService.loadUserByUsername(String identifier) as-is to preserve
behavior.
📍 PR 타입 (하나 이상 선택)
❗️ 관련 이슈 링크
📌 개요
카카오 로그인 사용자가 API 호출, 갱신, 로그아웃 시 실패하는 버그 수정
🔁 변경 사항
kakaoLogin, kakaoSignup : JWT 생성 시 userId -> kakaoId 변경
refresh, logout : Email 조회 실패 시 kakao로 재조회하도록 변경
📸 스크린샷
👀 기타 더 이야기해볼 점
✅ 체크 리스트
Summary by CodeRabbit
릴리스 노트