Skip to content

Conversation

@youngjun-k
Copy link
Contributor

@youngjun-k youngjun-k commented May 29, 2025

  • Removed outdated Redis script executors and consolidated token management logic.
  • Introduced a new RedisScriptExecutor interface for better abstraction and handling of Redis scripts.
  • Enhanced error handling in token management, replacing BaseException with AuthException for specific authentication errors.
  • Updated AuthService to streamline login and sign-up processes, improving member validation and token creation.
  • Refactored OAuthLoginRequest to simplify OAuth handling and removed unnecessary classes for cleaner codebase.
  • Improved member repository methods for better retrieval and error handling.

This refactor aims to enhance maintainability, security, and clarity in the authentication flow.

Summary by CodeRabbit

  • 신규 기능

    • 소셜 로그인 과정의 보안이 강화되어, 인증 절차를 우회한 계정 생성이 차단됩니다.
    • 소셜 로그인 메타데이터가 30분간 안전하게 저장·검증되어, 정보 불일치 시 회원가입이 차단됩니다.
    • 이메일 중복 여부를 로그인 시점에 바로 안내합니다.
    • 인증 및 권한 오류에 대해 구체적인 안내 메시지와 예외 처리가 제공됩니다.
  • 버그 수정

    • 닉네임 및 이메일 중복 체크 시 데이터베이스 제약 조건을 활용하여 불필요한 쿼리와 중복 에러를 줄였습니다.
  • 리팩터링

    • 소셜 인증 관련 서비스 구조가 간소화되고, 불필요한 DTO 및 인터페이스가 제거되었습니다.
    • OAuth 제공자 및 토큰 처리 로직이 통합·정리되었습니다.
  • 기타

    • 인증 관련 에러 코드 및 예외 응답이 세분화되어 사용자 경험이 개선되었습니다.
    • Redis 키 네이밍 규칙이 일관성 있게 변경되었습니다.

- Removed outdated Redis script executors and consolidated token management logic.
- Introduced a new RedisScriptExecutor interface for better abstraction and handling of Redis scripts.
- Enhanced error handling in token management, replacing BaseException with AuthException for specific authentication errors.
- Updated AuthService to streamline login and sign-up processes, improving member validation and token creation.
- Refactored OAuthLoginRequest to simplify OAuth handling and removed unnecessary classes for cleaner codebase.
- Improved member repository methods for better retrieval and error handling.

This refactor aims to enhance maintainability, security, and clarity in the authentication flow.
@coderabbitai
Copy link

coderabbitai bot commented May 29, 2025

"""

Walkthrough

이 변경은 소셜 로그인 절차의 보안 취약점을 해결하고, 소셜 인증 메타데이터를 Redis에 30분 TTL로 저장하여 검증을 강화했어. 로그인과 회원가입 로직이 명확히 분리되고, 데이터베이스 무결성은 예외 처리로 위임됐지. 불필요한 DTO와 인터페이스가 제거되고, 인증 전용 예외와 에러 코드가 추가됐어.

Changes

파일/그룹 변경 요약
auth/domain/SocialLink.java, auth/repository/SocialLinkRepository.java, auth/service/SocialLinkService.java 소셜 로그인 메타데이터를 Redis에 저장하고 검증하는 SocialLink 도메인, 저장소, 서비스 추가
auth/service/AuthService.java, member/repository/MemberWriter.java, member/repository/MemberReader.java, member/domain/Member.java, member/util/MemberUtils.java 인증/회원가입 로직 리팩토링, 예외 처리 개선, 데이터 무결성 위임, 회원 데이터 처리 유틸 추가
auth/service/FraudDetectionService.java, auth/service/RiskAssessment.java, member/repository/WithdrawalRecordReader.java, member/request/OAuthLoginInfo.java 사용하지 않는 DTO, 인터페이스, 리더 클래스 삭제
common/constants/AuthConstants.java, common/exception/code/ErrorCode.java 인증 관련 상수 및 에러 코드 추가/수정, 키 네이밍 규칙 변경
common/exception/AuthException.java, common/exception/handler/GlobalExceptionHandler.java 인증 전용 예외 및 글로벌 핸들러 추가
common/dto/request/OAuthLoginRequest.java DTO 변환 메서드 제거로 단순화
common/factory/OAuthProviderFactory.java OAuthProvider 동적 선택 로직 단순화 및 API 축소
common/provider/JwtTokenProvider.java, common/util/HashingUtil.java, auth/service/TokenService.java 토큰 해시 유틸리티 분리 및 적용
auth/executor/*.java, redis/RedisScriptExecutor.java, redis/RedisScriptName.java, redis/ScriptRegistry.java Redis 스크립트 관리 관련 패키지 이동 및 인터페이스 구현 명확화
auth/repository/RefreshTokenRepositoryImpl.java 클래스명 및 import 변경
resources/scripts/*.lua Redis 키 네이밍 규칙을 소문자+언더스코어로 통일

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthService
    participant SocialLinkService
    participant MemberRepository
    participant Redis

    Client->>AuthService: 소셜 로그인 요청 (OAuthLoginRequest)
    AuthService->>SocialLinkService: SocialLink 저장 (save)
    SocialLinkService->>Redis: SocialLink (TTL 30분) 저장
    AuthService->>MemberRepository: 이메일로 회원 조회
    alt 회원 없음
        AuthService-->>Client: 회원가입 안내
    else 회원 존재
        AuthService->>MemberRepository: validateLoginMember 호출
        alt 검증 실패
            AuthService-->>Client: 에러 반환
        else 검증 성공
            AuthService-->>Client: 로그인 성공, 토큰 발급
        end
    end

    Client->>AuthService: 회원가입 요청 (SignUpMemberRequest)
    AuthService->>SocialLinkService: SocialLink 검증 (verify)
    SocialLinkService->>Redis: SocialLink 조회 및 검증
    alt 검증 실패
        AuthService-->>Client: 에러 반환
    else 검증 성공
        AuthService->>MemberRepository: 회원 저장 시도
        alt 제약조건 위반
            AuthService-->>Client: 중복 에러 반환
        else 저장 성공
            AuthService-->>Client: 회원가입 완료
        end
    end
Loading

Possibly related PRs

Suggested labels

[REFACTOR]

Poem

__
소셜 링크 잠금, 보안은 철통,
Redis에 저장해 30분만 통통!
중복 닉네임? 이메일? DB가 지킨다네,
인증 예외도 새로 생겼지,
바보야, 이젠 우회는 금지!
리팩터링 완료, Mr. T도 감탄하지! 💪
__
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or ^^ anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@youngjun-k youngjun-k self-assigned this May 29, 2025
@coderabbitai coderabbitai bot changed the title ^^ Enhance social login security and metadata validation with Redis TTL May 29, 2025
@youngjun-k youngjun-k added the [FIX] 버그 수정 label May 29, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (2)
src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java (2)

15-28: 🛠️ Refactor suggestion

예외 처리 체인 탐색이 똑똑하네, 하지만 개선할 점이 있어!

cause chain을 따라가면서 RedisCommandExecutionException을 찾는 로직은 좋은데, 무한 루프 방지가 없네, fool!

무한 루프 방지를 추가해:

 default void handleRedisException(RedisSystemException e) {
     // Check if the cause is a RedisCommandExecutionException
     Throwable cause = e.getCause();
+    int depth = 0;
+    final int MAX_DEPTH = 10;
-    while (cause != null) {
+    while (cause != null && depth < MAX_DEPTH) {
         if (cause instanceof RedisCommandExecutionException) {
             handleRedisScriptError(cause.getMessage());
             return;
         }
         cause = cause.getCause();
+        depth++;
     }

30-33: ⚠️ Potential issue

쿠키 삭제하고 예외 던지는 건 좋은데, 보안 측면에서 문제가 있어!

에러 메시지를 그대로 노출하면 내부 정보가 leak될 수 있어, fool! Redis 스크립트 에러는 민감한 정보를 포함할 수 있거든.

에러 메시지를 일반화하는 게 어때:

 default void handleRedisScriptError(String errorMessage) {
     HttpResponseUtil.addCookie(AuthConstants.REFRESH_TOKEN_HEADER_NAME, "", 0);
-    throw new BaseException(errorMessage, ErrorCode.INTERNAL_SERVER_ERROR);
+    // 보안을 위해 일반적인 에러 메시지 사용
+    throw new BaseException("Redis operation failed", ErrorCode.INTERNAL_SERVER_ERROR);
 }
🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 30-30: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: HttpResponseUtil.addCookie(AuthConstants.REFRESH_TOKEN_HEADER_NAME, "", 0);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)

🧹 Nitpick comments (4)
src/main/java/com/juu/juulabel/redis/ScriptRegistry.java (1)

15-18: 스트림 API 사용이 깔끔하네, 하지만 조심해야 할 게 있어!

executors 리스트에 중복된 클래스 이름이 있으면 마지막 것만 남고 나머지는 덮어씌워져, fool!

중복 체크를 추가하는 게 어떨까:

 public ScriptRegistry(List<RedisScriptExecutor<?, ?>> executors) {
-    this.scripts = executors.stream()
-            .collect(Collectors.toMap(e -> e.getClass().getSimpleName(), Function.identity()));
+    this.scripts = executors.stream()
+            .collect(Collectors.toMap(
+                e -> e.getClass().getSimpleName(), 
+                Function.identity(),
+                (existing, replacement) -> {
+                    throw new IllegalStateException(
+                        "Duplicate executor class name: " + existing.getClass().getSimpleName());
+                }));
 }
src/main/java/com/juu/juulabel/common/factory/OAuthProviderFactory.java (1)

32-40: 코드 가독성을 개선해야 해, fool!

인라인으로 액세스 토큰을 가져오는 부분이 읽기 어려워. 변수로 분리하면 더 명확해질 거야!

 public OAuthUser getOAuthUser(OAuthLoginRequest oAuthLoginRequest) {
     Provider provider = oAuthLoginRequest.provider();
-    String accessToken = getOAuthToken(
-            provider,
-            oAuthLoginRequest.redirectUri(),
-            oAuthLoginRequest.code()).accessToken();
+    OAuthToken token = getOAuthToken(
+            provider,
+            oAuthLoginRequest.redirectUri(),
+            oAuthLoginRequest.code());
+    String accessToken = token.accessToken();

     return getOAuthProvider(provider).getOAuthUser(accessToken);
 }
src/main/java/com/juu/juulabel/member/repository/MemberWriter.java (2)

76-91: 에러 메시지 파싱 로직 개선이 필요합니다

I pity the fool who relies on error message strings! 현재 구현은 동작하지만, 데이터베이스별로 에러 메시지 형식이 다를 수 있습니다:

  1. MySQL과 PostgreSQL의 에러 메시지 형식이 다름
  2. 데이터베이스 버전 업그레이드 시 메시지가 변경될 수 있음
  3. 제약조건 이름이 변경되면 코드도 수정해야 함

더 안정적인 방법을 고려해보세요:

private boolean isNicknameConstraintViolation(String errorMessage) {
    String lowerCaseMessage = errorMessage.toLowerCase();
+   // Consider using Spring's DataAccessException hierarchy
+   // or database-specific error codes instead of message parsing
    return lowerCaseMessage.contains("unique_nickname") ||
            (lowerCaseMessage.contains("duplicate entry") && lowerCaseMessage.contains("unique_nickname"));
}

장기적으로는 Spring의 DuplicateKeyException이나 데이터베이스별 에러 코드를 활용하는 것이 더 안정적일 수 있습니다.


58-60: 알 수 없는 제약조건 위반 시 로깅 추가를 권장합니다

I pity the fool who doesn't log important errors! 인식하지 못한 제약조건 위반이 발생했을 때 디버깅을 위해 로그를 남기는 것이 좋습니다.

// Re-throw the original exception if it's not a recognized constraint violation
+log.warn("Unhandled constraint violation: {}", errorMessage, e);
throw new InvalidParamException(ErrorCode.INTERNAL_SERVER_ERROR);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fceebc and 4ebdf04.

📒 Files selected for processing (33)
  • docs/pr/PR-141-refactor---auth.md (1 hunks)
  • src/main/java/com/juu/juulabel/auth/domain/SocialLink.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/executor/LoginRefreshTokenScriptExecutor.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/executor/RevokeRefreshTokenByIndexKeyExecutor.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/executor/RotateRefreshTokenScriptExecutor.java (2 hunks)
  • src/main/java/com/juu/juulabel/auth/executor/SaveRefreshTokenScriptExecutor.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/repository/RefreshTokenRepositoryImpl.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/repository/SocialLinkRepository.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/service/AuthService.java (2 hunks)
  • src/main/java/com/juu/juulabel/auth/service/FraudDetectionService.java (0 hunks)
  • src/main/java/com/juu/juulabel/auth/service/RiskAssessment.java (0 hunks)
  • src/main/java/com/juu/juulabel/auth/service/SocialLinkService.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/service/TokenService.java (3 hunks)
  • src/main/java/com/juu/juulabel/common/constants/AuthConstants.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/dto/request/OAuthLoginRequest.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/exception/AuthException.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/exception/handler/GlobalExceptionHandler.java (3 hunks)
  • src/main/java/com/juu/juulabel/common/factory/OAuthProviderFactory.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/provider/JwtTokenProvider.java (0 hunks)
  • src/main/java/com/juu/juulabel/common/util/HashingUtil.java (1 hunks)
  • src/main/java/com/juu/juulabel/member/domain/Member.java (5 hunks)
  • src/main/java/com/juu/juulabel/member/repository/MemberReader.java (2 hunks)
  • src/main/java/com/juu/juulabel/member/repository/MemberWriter.java (1 hunks)
  • src/main/java/com/juu/juulabel/member/repository/WithdrawalRecordReader.java (0 hunks)
  • src/main/java/com/juu/juulabel/member/request/OAuthLoginInfo.java (0 hunks)
  • src/main/java/com/juu/juulabel/member/util/MemberUtils.java (1 hunks)
  • src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java (1 hunks)
  • src/main/java/com/juu/juulabel/redis/RedisScriptName.java (1 hunks)
  • src/main/java/com/juu/juulabel/redis/ScriptRegistry.java (1 hunks)
  • src/main/resources/scripts/login_refresh_token.lua (1 hunks)
  • src/main/resources/scripts/rotate_refresh_token.lua (2 hunks)
  • src/main/resources/scripts/save_refresh_token.lua (1 hunks)
💤 Files with no reviewable changes (5)
  • src/main/java/com/juu/juulabel/member/request/OAuthLoginInfo.java
  • src/main/java/com/juu/juulabel/auth/service/FraudDetectionService.java
  • src/main/java/com/juu/juulabel/common/provider/JwtTokenProvider.java
  • src/main/java/com/juu/juulabel/member/repository/WithdrawalRecordReader.java
  • src/main/java/com/juu/juulabel/auth/service/RiskAssessment.java
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/main/java/com/juu/juulabel/auth/service/TokenService.java (1)
src/main/java/com/juu/juulabel/common/util/HashingUtil.java (1)
  • HashingUtil (8-23)
src/main/java/com/juu/juulabel/auth/executor/RotateRefreshTokenScriptExecutor.java (1)
src/main/java/com/juu/juulabel/common/util/HttpResponseUtil.java (1)
  • HttpResponseUtil (8-46)
src/main/java/com/juu/juulabel/auth/domain/SocialLink.java (3)
src/main/java/com/juu/juulabel/common/exception/AuthException.java (1)
  • Getter (6-24)
src/main/java/com/juu/juulabel/member/domain/Member.java (1)
  • Getter (15-137)
src/main/java/com/juu/juulabel/common/constants/AuthConstants.java (1)
  • NoArgsConstructor (8-23)
🔇 Additional comments (38)
src/main/java/com/juu/juulabel/common/util/HashingUtil.java (1)

8-12: 아, 이 바보 같은 유틸리티 클래스 패턴 제대로 구현했네!

final 클래스에 private 생성자로 인스턴스화를 막는 건 정말 좋은 패턴이야, fool! AssertionError를 던지는 것도 누군가 리플렉션으로 생성자 호출하는 걸 막아주지.

src/main/java/com/juu/juulabel/auth/executor/SaveRefreshTokenScriptExecutor.java (1)

16-16: 패키지 리팩토링 깔끔하게 했네, fool!

Redis 관련 클래스들을 별도 패키지로 분리하는 건 관심사 분리 관점에서 좋은 결정이야.

src/main/java/com/juu/juulabel/redis/ScriptRegistry.java (1)

1-1: Redis 패키지로 이동한 게 딱 맞네, fool!

스크립트 레지스트리가 redis 패키지에 있는 게 훨씬 논리적이야.

src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java (1)

1-1: Redis 패키지로 이동한 게 완벽해, fool!

Redis 스크립트 실행 관련 인터페이스가 redis 패키지에 있는 게 맞지.

src/main/java/com/juu/juulabel/auth/executor/LoginRefreshTokenScriptExecutor.java (1)

15-15: 수고했어요, fool! 이 import 추가는 완벽해!

Redis 관련 인터페이스를 전용 패키지로 이동시키는 리팩터링의 일환으로 보이는데, 이미 구현하고 있던 인터페이스에 대한 import를 추가한 것이니 아무 문제 없어요. I pity the fool who doesn't organize their packages properly!

src/main/resources/scripts/rotate_refresh_token.lua (2)

1-3: 명명 규칙 표준화가 훌륭해요, fool!

Redis 키 명명 규칙을 PascalCase에서 lowercase with underscores로 표준화한 것이 좋습니다. I pity the fool who doesn't keep their naming conventions consistent! 이런 일관성은 유지보수성을 크게 향상시켜요.


23-23: 패턴 업데이트도 완벽해요!

revokeAllMemberTokens 함수의 스캔 패턴도 새로운 명명 규칙에 맞게 업데이트했군요. 코드 전반에 걸친 일관성을 보장하는 좋은 변경사항이에요. I pity the fool who forgets to update patterns when changing naming conventions!

src/main/java/com/juu/juulabel/auth/service/TokenService.java (2)

9-9: HashingUtil import 추가가 현명한 선택이에요!

토큰 해싱 로직을 전용 유틸리티 클래스로 중앙화하는 것은 관심사 분리에 훌륭한 접근이에요. I pity the fool who doesn't centralize their utility functions!


72-72: 해싱 메서드 교체가 완벽해요, fool!

jwtTokenProvider.hashToken()에서 HashingUtil.hashSha256()로 변경한 것이 좋습니다. 관련 코드 스니펫을 보니 HashingUtil 구현이 견고해요:

  • SHA-256 알고리즘 사용
  • URL-safe Base64 인코딩
  • 적절한 예외 처리
  • 인스턴스화 불가능한 유틸리티 클래스 설계

I pity the fool who doesn't use proper utility classes for common operations!

Also applies to: 109-109

src/main/java/com/juu/juulabel/auth/repository/RefreshTokenRepositoryImpl.java (2)

6-7: Redis 패키지 재구성이 훌륭해요!

Redis 스크립트 관련 클래스들을 전용 redis 패키지로 이동시킨 것이 좋은 조직화예요. I pity the fool who doesn't organize their packages properly! 이런 구조화는 코드 관리와 유지보수성을 크게 향상시켜요.


14-14: 클래스명 변경이 더 명확해요, fool!

RedisRefreshTokenRepository에서 RefreshTokenRepositoryImpl로 변경한 것이 더 명확한 명명이에요. Implementation 클래스임을 명시적으로 나타내는 좋은 네이밍 컨벤션이죠. I pity the fool who doesn't follow proper naming conventions!

src/main/resources/scripts/login_refresh_token.lua (1)

1-2: 변경된 Redis 키 네이밍 컨벤션 반영
바보 같은 혼용은 용서 못해! Lua 스크립트 주석에서 PascalCase 대신 snake_case(refresh_token, refresh_index)로 예시 키 네이밍을 일관되게 업데이트했으니 확인해봐.

src/main/resources/scripts/save_refresh_token.lua (1)

1-2: 키 네이밍 예시를 snake_case로 통일
파스칼 케이스는 이제 그만! 설명 주석에서 refresh_token, refresh_index로 통일했으니 바보 같은 혼용은 안 하길 바란다.

src/main/java/com/juu/juulabel/auth/executor/RevokeRefreshTokenByIndexKeyExecutor.java (1)

14-14:

Details

✅ Verification successful

RedisScriptExecutor 인터페이스 임포트 적용
추상화 레벨을 올리기 위해 새로 com.juu.juulabel.redis.RedisScriptExecutor를 임포트했네. 이 변경 안 하면 진짜 바보일 걸? 경로와 handleRedisException 제공 여부를 확인해봐.


🏁 Script executed:

#!/bin/bash
# RedisScriptExecutor 인터페이스 위치 및 handleRedisException 정의 확인
rg -n "interface RedisScriptExecutor" -R src/main/java
rg -n "handleRedisException" -R src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java

Length of output: 960


Hey, 바보 취급하고 싶지 않으면 이걸로 다시 확인해! 난 바보를 불쌍히 여기는 놈이거든!


🏁 Script executed:

#!/bin/bash
# RedisScriptExecutor 인터페이스 정의와 handleRedisException 구현 여부 재확인
rg -n 'interface RedisScriptExecutor' src/main/java
rg -n 'handleRedisException' src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java

Length of output: 321


확인 완료: RedisScriptExecutor 인터페이스와 handleRedisException 구현이 존재합니다

인터페이스와 기본 예외 처리 메서드가 아래 위치에서 정상적으로 확인되었으니 변경 사항은 그대로 유지해도 좋습니다. 난 바보를 불쌍히 여기지만, 이번엔 문제가 없으니 안심해도 돼!

• src/main/java/com/juu/juulabel/redis/RedisScriptExecutor.java
– Line 12: public interface RedisScriptExecutor<T, R>
– Line 15: default void handleRedisException(RedisSystemException e) { … }

src/main/java/com/juu/juulabel/auth/repository/SocialLinkRepository.java (1)

1-9: 새로운 SocialLinkRepository 인터페이스 추가
소셜 링크 도메인 CRUD를 위한 CrudRepository<SocialLink, String> 확장이네. 이걸 무시하는 바보를 난 불쌍히 여긴다! 필요 시 커스텀 메서드를 추가하는 것도 고려해봐.

src/main/java/com/juu/juulabel/redis/RedisScriptName.java (1)

5-11: RedisScriptName enum 주석 및 상수 업데이트
리프레시 토큰 스크립트 구분을 위해 // Refresh Token 주석을 넣고, REVOKE_REFRESH_TOKEN_BY_INDEX_KEY 뒤에 쉼표를 일관성 있게 추가했어. 이런 기본도 못 챙기는 바보는 안 되지!

src/main/java/com/juu/juulabel/auth/executor/RotateRefreshTokenScriptExecutor.java (2)

18-18: 새로운 예외 처리와 패키지 재구성이 올바르게 적용되었어, fool!

AuthException 임포트와 Redis 패키지 재구성이 적절히 반영되었네. I pity the fool who doesn't organize their packages properly!

Also applies to: 21-21


57-61: 인증 관련 예외 처리가 훨씬 명확해졌어, fool!

BaseException 대신 AuthException을 사용하는 것이 인증 도메인의 책임을 명확히 하고 에러 추적을 개선하네. I pity the fool who uses generic exceptions for specific authentication errors! 각 에러 코드(REFRESH_TOKEN_NOT_FOUND, REFRESH_TOKEN_REUSE_DETECTED, DEVICE_ID_MISMATCH)가 적절하게 매핑되어 있어.

src/main/java/com/juu/juulabel/member/repository/MemberReader.java (2)

13-13: Optional 임포트가 필요하다, fool!

새로운 getOptionalByEmail 메서드를 위한 적절한 임포트네. I pity the fool who forgets their imports!


32-34: 유연한 회원 조회 메서드 추가가 훌륭해, fool!

getOptionalByEmail 메서드는 예외를 던지지 않는 대안을 제공해서 인증 서비스에서 더 유연한 제어 흐름을 가능하게 하네. I pity the fool who always throws exceptions when Optional can handle absence gracefully! 기존 getByEmail 메서드와 함께 두 가지 사용 패턴을 모두 지원할 수 있어.

src/main/java/com/juu/juulabel/common/dto/request/OAuthLoginRequest.java (1)

8-11: OAuth 요청 레코드 단순화가 완벽해, fool!

toDto() 메서드를 제거하고 불필요한 데이터 변환 계층을 없앤 것이 현명하네. I pity the fool who keeps unnecessary mapping methods! 유효성 검증 어노테이션과 한국어 오류 메시지가 적절히 유지되고 있어. 레코드가 더 간결하고 유지보수하기 쉬워졌다.

src/main/java/com/juu/juulabel/member/util/MemberUtils.java (1)

52-62: 회원 데이터 처리 중앙화가 좋은 접근이야, fool!

null 체크와 함께 alcohol types와 terms agreements 처리를 하나의 메서드로 통합한 것이 AuthService의 복잡성을 줄여주네. I pity the fool who scatters member processing logic everywhere!

src/main/java/com/juu/juulabel/member/domain/Member.java (2)

34-34: I pity the fool who doesn't enforce database constraints! 좋은 개선이야!

닉네임 필드에 unique = true 제약 조건을 추가한 건 데이터베이스 레벨에서 무결성을 보장하는 올바른 접근이야. 이제 애플리케이션 레벨의 중복 검사 대신 데이터베이스가 직접 처리하게 되어 더 안전하고 효율적이지.


78-88: I pity the fool who doesn't like clean code! 멤버 생성 로직이 깔끔해졌어!

빌더 패턴을 사용한 멤버 생성 로직이 간결하고 명확해졌어. 기본값들이 명시적으로 설정되어 있어서 의도가 명확하게 드러나지.

src/main/java/com/juu/juulabel/common/exception/AuthException.java (1)

1-24: I pity the fool who doesn't separate authentication concerns! 인증 전용 예외 클래스 설계가 훌륭해!

AuthException 클래스 설계가 매우 잘 되어 있어:

  • BaseException을 확장해서 일관성 유지
  • 다양한 생성자로 유연성 제공
  • 기본 에러 코드를 HIGH_SECURITY_RISK로 설정한 것이 보안상 안전한 접근
  • 인증 관련 예외와 일반 비즈니스 예외의 명확한 분리

이런 설계는 인증/인가 오류를 더 정확하게 분류하고 처리할 수 있게 해줘.

src/main/java/com/juu/juulabel/auth/service/SocialLinkService.java (2)

23-33: I pity the fool who doesn't hash sensitive data! 소셜 링크 저장 로직이 보안을 잘 고려했어!

save 메서드의 구현이 보안 측면에서 훌륭해:

  • 이메일을 SHA-256으로 해싱해서 개인정보 보호
  • 디바이스 ID, User Agent, IP 주소 등 클라이언트 메타데이터 수집으로 추가 검증 가능
  • Redis TTL을 통한 임시 저장으로 보안 위험 최소화

이런 접근은 소셜 로그인 우회 공격을 효과적으로 방지할 수 있어.


35-46: I pity the fool who doesn't validate client metadata! 검증 로직이 철저해!

verify 메서드의 보안 검증이 매우 포괄적이야:

  • 해시된 이메일로 소셜 링크 조회
  • 소셜 링크가 없으면 AuthException 발생
  • 프로바이더, 프로바이더 ID, 클라이언트 메타데이터 모두 검증
  • 사용 후 markAsUsed() 호출로 재사용 방지

이런 다층 검증은 소셜 로그인 보안을 크게 강화시켜.

src/main/java/com/juu/juulabel/common/exception/handler/GlobalExceptionHandler.java (3)

35-38: I pity the fool who doesn't handle parameter validation! InvalidParamException 핸들러가 깔끔해!

InvalidParamException 핸들러가 간단하고 효율적이야. 별도의 로깅 없이 에러 코드만 반환하는 것이 적절해 - 파라미터 검증 오류는 일반적으로 클라이언트 측 문제이니까.


40-45: I pity the fool who doesn't take authentication seriously! AuthException 핸들러가 완벽해!

AuthException 핸들러의 구현이 보안 관점에서 훌륭해:

  • 로깅으로 보안 이벤트 추적 가능
  • Sentry 리포팅으로 모니터링 강화
  • 에러 코드와 메시지를 모두 포함한 상세 응답
  • 인증 관련 오류의 특별한 처리 필요성을 잘 반영

이런 접근은 보안 사고 대응과 디버깅에 큰 도움이 될 거야.


47-51: I pity the fool who doesn't reduce log noise! 로깅 제거가 현명한 판단이야!

BaseException 핸들러에서 로깅을 제거한 건 좋은 개선이야. Sentry 리포팅은 유지하면서 로그 노이즈는 줄여서, 모니터링은 계속 되지만 로그는 더 깔끔해졌어.

src/main/java/com/juu/juulabel/auth/domain/SocialLink.java (1)

1-110: 전반적인 구현은 훌륭해, 잘했어!

소셜 링크 보안 기능이 잘 구현됐어:

  • Redis TTL로 30분 만료 시간 설정 ✓
  • 일회용 검증 로직 ✓
  • 빌더 패턴 사용 ✓

Mr. T가 인정하는 solid한 코드야!

src/main/java/com/juu/juulabel/common/factory/OAuthProviderFactory.java (1)

24-30: Switch expression 사용이 멋져!

Java의 현대적인 기능을 잘 활용했어. Default 케이스로 예외 처리도 완벽해!

src/main/java/com/juu/juulabel/auth/service/AuthService.java (1)

36-60: 보안 강화가 훌륭해!

소셜 링크 검증으로 인증 우회를 막는 게 정말 똑똑한 방법이야:

  • 신규 회원은 소셜 링크 저장 ✓
  • 기존 회원은 provider 검증 ✓
  • 명확한 관심사 분리 ✓

Mr. T가 자랑스러워해!

src/main/java/com/juu/juulabel/common/exception/code/ErrorCode.java (2)

35-36: 이름 변경이 적절합니다!

I pity the fool who confuses Authentication with Authorization! "Authorization"으로 변경한 것이 정확합니다. 이 섹션의 에러들은 권한 확인과 관련되어 있으니까요.


40-52: 새로운 AuthException 에러 코드들이 잘 정의되었습니다!

I pity the fool who doesn't separate authentication errors properly! 보안 관련 에러들을 따로 분리한 건 훌륭한 결정입니다:

  • 인증 실패는 401 (UNAUTHORIZED)
  • 권한/보안 위반은 403 (FORBIDDEN)
  • 일반적인 요청 오류는 400 (BAD_REQUEST)

HTTP 상태 코드 매핑이 RESTful 원칙에 잘 부합합니다.

docs/pr/PR-141-refactor---auth.md (2)

16-39: 보안 취약점 해결 방안이 훌륭합니다!

I pity the fool who doesn't secure their social login! Redis TTL 기반 검증은 정말 똑똑한 해결책입니다. 30분 TTL로 소셜 로그인 메타데이터를 저장하고 회원가입 시 검증하는 방식이 보안을 크게 강화합니다.


66-88: 데이터베이스 최적화가 인상적입니다!

I pity the fool who makes unnecessary database queries! 쿼리를 4개에서 1개로 줄인 건 정말 멋진 최적화입니다. 낙관적 접근법(Optimistic approach)을 사용해서 대부분의 경우 단일 INSERT로 처리하고, 충돌이 발생할 때만 예외를 처리하는 방식이 효율적입니다.

단, 데이터베이스에 적절한 유니크 제약조건이 설정되어 있는지 확인이 필요합니다!

src/main/java/com/juu/juulabel/member/repository/MemberWriter.java (1)

28-34: 예외 처리 로직이 잘 구현되었습니다!

I pity the fool who doesn't handle database exceptions properly! 데이터베이스 제약조건 위반을 비즈니스 예외로 변환하는 방식이 깔끔합니다.

- Simplified error messages in SocialLink to enhance security and clarity.
- Updated AuthService to use orElseGet for better performance and readability.
- Corrected a typo in AuthConstants for the refresh token prefix.
- Enhanced IpAddressExtractor to utilize orElseGet for improved null handling.
- Refactored FollowReader to use orElseGet for consistency in null returns.

These changes aim to improve maintainability and clarity across the authentication and follow management components.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main/java/com/juu/juulabel/follow/repository/FollowReader.java (1)

24-26: I pity the fool who uses .orElseGet() when .orElse() is better, fool!

야, 이 변경사항이 불필요해! null 같은 리터럴 값에는 .orElse(null).orElseGet(() -> null)보다 더 적절해. .orElseGet()은 비싼 연산이나 부작용이 있는 메서드 호출에만 사용해야 해. 여기서는 불필요한 람다 오버헤드만 추가하고 있어, fool!

다음 diff로 되돌리는 걸 권장해:

-                .orElseGet(() -> null);
+                .orElse(null);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ebdf04 and 446884e.

📒 Files selected for processing (6)
  • src/main/java/com/juu/juulabel/auth/domain/SocialLink.java (1 hunks)
  • src/main/java/com/juu/juulabel/auth/service/AuthService.java (2 hunks)
  • src/main/java/com/juu/juulabel/common/constants/AuthConstants.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/com/juu/juulabel/common/util/IpAddressExtractor.java (1 hunks)
  • src/main/java/com/juu/juulabel/follow/repository/FollowReader.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/juu/juulabel/common/util/IpAddressExtractor.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/com/juu/juulabel/common/constants/AuthConstants.java
  • src/main/java/com/juu/juulabel/auth/service/AuthService.java
  • src/main/java/com/juu/juulabel/auth/domain/SocialLink.java
🔇 Additional comments (4)
src/main/java/com/juu/juulabel/common/exception/code/ErrorCode.java (4)

35-39: 인증과 권한 구분이 명확해졌어, 이걸 안 하는 fool들을 불쌍하게 여기지!

"Authentication"에서 "Authorization"으로 주석 변경이 의미론적으로 정확해. DEVICE_ID_REQUIRED와 OAUTH_PROVIDER_NOT_FOUND는 실제로 권한 부여(authorization) 관련 에러니까 말이야.


40-52: 새로운 AuthException 섹션이 보안을 강화했어, I pity the fool who tries to hack this!

소셜 로그인 보안 검증을 위한 새로운 에러 코드들이 추가됐는데, 이건 정말 좋은 보안 강화야:

  • SOCIAL_LINK_NOT_FOUND, SOCIAL_LINK_ALREADY_USED: 소셜 링크 생명주기 관리
  • PROVIDER_ID_MISMATCH, USER_AGENT_MISMATCH: 세션 하이재킹 방지
  • HIGH_SECURITY_RISK: 포괄적 보안 위협 감지

HTTP 상태 코드 매핑도 적절해. FORBIDDEN (403)은 보안 위반에 맞고, BAD_REQUEST (400)는 클라이언트 요청 오류에 적합하지.


44-44: 토큰 재사용 감지의 HTTP 상태 코드 변경이 보안 관점에서 더 정확해, fool!

REFRESH_TOKEN_REUSE_DETECTEDFORBIDDEN (403)에서 UNAUTHORIZED (401)로 변경한 건 정확한 판단이야. 토큰 재사용은 인증 자체의 문제지, 권한 부족 문제가 아니거든. 이렇게 하면 클라이언트가 토큰을 다시 얻어야 한다는 걸 명확히 알 수 있어.


49-49: DEVICE_ID_MISMATCH도 보안 강화를 위해 올바른 상태 코드로 변경됐어!

AI 요약에 따르면 DEVICE_ID_MISMATCHBAD_REQUEST (400)에서 FORBIDDEN (403)으로 변경됐다고 하는데, 이건 보안 위반에 대한 더 적절한 응답이야. 디바이스 ID 불일치는 잠재적 보안 위협이니까 403이 맞아.

@youngjun-k youngjun-k merged commit 3818004 into develop May 29, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[FIX] 버그 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants