Skip to content

Conversation

@yw6938
Copy link
Collaborator

@yw6938 yw6938 commented Dec 24, 2025

#️⃣연관된 이슈

ex) #911

📝작업 내용

다중 리프레시 토큰 지원

  • 기존에는 한 기기에서만 로그인 가능
  • 리프레시 토큰을 리스트로 관리해 여러 기기에서 사용 가능

고려했던 점

  • 만료되지 않은 단일 리프레시 토큰을 여러 기기에 공유하는 방식을 고려
  • 리스트가 더 편하고 보안성 면에서 우수해 리스트 채택

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 새로운 기능

    • 사용자가 여러 동시 활성 세션(다중 갱신 토큰)을 보유하고 관리할 수 있도록 지원합니다.
  • 개선 사항

    • 로그인·로그아웃·토큰 갱신·프로필 업데이트 흐름에서 토큰 관리가 컬렉션 기반으로 개선되어 안정성 및 보안이 향상되었습니다.
    • 쿠키 및 갱신 토큰 처리 로직이 일관되게 정리되어 오류 가능성이 감소했습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@yw6938 yw6938 requested a review from lepitaaar December 24, 2025 11:03
@yw6938 yw6938 self-assigned this Dec 24, 2025
@yw6938 yw6938 added ✨ Feature 기능 개발 💾 BE Backend labels Dec 24, 2025
@vercel
Copy link

vercel bot commented Dec 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
moadong Ready Ready Preview, Comment Dec 24, 2025 11:15am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • 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

Walkthrough

사용자 엔티티의 단일 refreshToken 필드를 리스트(refreshTokens)로 변경하고, 컬렉션 관리 메서드(add/replace/remove/removeAll) 추가. 저장소 쿼리명과 서비스의 로그인/로그아웃/갱신/업데이트/비밀번호 재설정 로직이 새 컬렉션 구조에 맞게 조정됨 (쿠키 생성/처리도 연동).

Changes

Cohort / File(s) 변경 요약
User 엔티티
backend/src/main/java/moadong/user/entity/User.java
refreshToken: RefreshTokenrefreshTokens: List<RefreshToken>로 변경(@Field("refreshTokens"), @Builder.Default로 빈 ArrayList 초기화). 컬렉션 관리 메서드 추가: addRefreshToken, replaceRefreshToken, removeRefreshToken, removeAllRefreshTokens. 기존 updateRefreshToken 제거. List/ArrayList 임포트 추가.
저장소 쿼리
backend/src/main/java/moadong/user/repository/UserRepository.java
쿼리 메서드명 변경: findUserByRefreshToken_Token(...)findUserByRefreshTokens_Token(...) (토큰 검색 대상 컬렉션명 반영).
서비스 로직
backend/src/main/java/moadong/user/service/UserCommandService.java
로그인: 새 토큰을 컬렉션에 추가; 로그아웃: 컬렉션에서 특정 토큰 제거(토큰으로 사용자 조회 변경); 리프레시: 토큰 존재 여부 확인 후 만료 검사 및 replaceRefreshToken 호출; 사용자 업데이트/임시비밀번호(리셋): 모든 리프레시 토큰 제거 및 새 토큰 추가. 쿠키 생성/갱신 로직이 새 토큰 값에 맞게 조정됨.

Sequence Diagram(s)

sequenceDiagram
  participant Client as 클라이언트
  participant Service as UserCommandService
  participant Repo as UserRepository
  participant DB as MongoDB
  Note over Service,Repo: 로그인 / 토큰 갱신 흐름 (다중 refreshTokens)
  Client->>Service: 로그인 요청 (credentials)
  Service->>Repo: findByEmail(...)
  Repo->>DB: 사용자 조회
  DB-->>Repo: 사용자 도큐먼트 (refreshTokens: [])
  Repo-->>Service: User
  Service->>Service: generateRefreshToken()
  Service->>User: addRefreshToken(newRefreshToken)
  Service->>Repo: save(User)
  Repo->>DB: 사용자 업데이트 (refreshTokens에 새 토큰 추가)
  DB-->>Repo: 저장 완료
  Repo-->>Service: 저장된 User
  Service-->>Client: 응답 + Set-Cookie (newRefreshToken.token)
Loading

Estimated code review effort

🎯 3 (보통) | ⏱️ ~20분

Possibly related issues

  • MOA-405: 관리자계정에 다중 refreshToken을 지원한다 — 본 PR은 사용자 엔티티에 다중 refreshToken 컬렉션을 도입하는 작업으로 해당 목표와 일치함.
  • [feature] MOA-405 관리자계정에 다중 refreshToken을 지원한다 #911: 단일 refreshToken → 다중 refreshTokens 변경 관련 이슈 — 메서드/쿼리/서비스 로직 업데이트가 이 이슈의 요구사항과 직접적으로 부합함.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing support for multiple refresh tokens in admin accounts to enable simultaneous login from multiple devices.
Linked Issues check ✅ Passed The pull request successfully implements the core objective from MOA-405: changing from single to multiple refresh token support with new collection management methods, repository query updates, and service layer modifications.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated objective of adding multiple refresh token support; no unrelated modifications were introduced.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#911-admin-multi-refresh-token-MOA-405

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 91fbc3d and 32ee4ac.

📒 Files selected for processing (1)
  • backend/src/main/java/moadong/user/service/UserCommandService.java
🔇 Additional comments (6)
backend/src/main/java/moadong/user/service/UserCommandService.java (6)

79-79: 다중 토큰 지원을 위한 올바른 구현입니다.

단일 토큰 업데이트에서 컬렉션에 토큰을 추가하는 방식으로 변경되어 여러 기기에서 동시 로그인이 가능합니다.


88-92: 로그아웃 로직이 다중 토큰 구조에 맞게 올바르게 변경되었습니다.

특정 토큰만 제거하여 다른 기기의 로그인 세션은 유지됩니다.


123-123: 토큰 갱신 로직이 올바르게 구현되었습니다.

특정 토큰만 새 토큰으로 교체하여 다른 기기의 세션에 영향을 주지 않습니다.


148-150: 비밀번호 변경 시 모든 토큰을 제거하는 보안 처리가 적절합니다.

모든 기기에서 재로그인을 요구하여 계정 보안을 강화합니다.


154-154: 쿠키 생성이 새로운 RefreshToken 구조에 맞게 올바르게 업데이트되었습니다.


169-169: 임시 비밀번호 발급 시 모든 토큰을 제거하는 보안 처리가 적절합니다.

비밀번호 재설정 후 모든 기존 세션을 무효화하여 보안을 강화합니다.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 24, 2025

Test Results

75 tests   72 ✅  19s ⏱️
14 suites   3 💤
14 files     0 ❌

Results for commit 32ee4ac.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (3)
backend/src/main/java/moadong/user/service/UserCommandService.java (1)

79-80: 토큰 개수 제한 및 정리 전략을 고려하세요.

현재 구현에서는 사용자당 리프레시 토큰 개수에 제한이 없습니다. 다음 사항들을 검토하시기 바랍니다:

  1. 토큰 개수 제한: 사용자가 로그아웃 없이 계속 로그인하면 토큰이 무제한으로 누적될 수 있습니다. 최대 토큰 개수를 설정하고 오래된 토큰을 자동으로 제거하는 정책을 고려하세요 (예: 최대 5개 기기).

  2. 만료된 토큰 정리: 만료된 토큰이 DB에 계속 남아있습니다. 주기적인 정리 작업(scheduled job)이나 로그인 시 만료 토큰 제거 로직을 추가하는 것이 좋습니다.

  3. 기기 식별: 현재는 어떤 토큰이 어떤 기기에서 사용되는지 추적할 수 없습니다. 향후 "다른 기기에서 로그아웃" 같은 기능을 위해 기기 정보(User-Agent, 기기명 등)를 RefreshToken에 포함하는 것을 고려하세요.

backend/src/main/java/moadong/user/entity/User.java (2)

107-118: 토큰을 찾지 못한 경우의 처리를 개선하세요.

replaceRefreshToken 메서드가 oldToken을 찾지 못하면 아무 작업 없이 조용히 반환됩니다. 이는 토큰 교체가 예상되지만 실제로 발생하지 않는 버그를 숨길 수 있습니다.

다음 중 하나를 고려하세요:

  • 토큰을 찾지 못한 경우 예외를 던지기
  • 경고 로그 남기기
  • 반환 타입을 boolean으로 변경하여 성공 여부를 알리기
🔎 예외 처리 추가 제안
 public void replaceRefreshToken(String oldToken, RefreshToken newToken) {
     if (this.refreshTokens == null) {
         this.refreshTokens = new ArrayList<>();
-        return;
+        throw new IllegalStateException("토큰 교체 실패: 리프레시 토큰 목록이 비어있습니다.");
     }
     for (int i = 0; i < this.refreshTokens.size(); i++) {
         if (this.refreshTokens.get(i).getToken().equals(oldToken)) {
             this.refreshTokens.set(i, newToken);
             return;
         }
     }
+    throw new IllegalArgumentException("토큰 교체 실패: 기존 토큰을 찾을 수 없습니다.");
 }

127-133: 전체 토큰 제거 메서드의 null 처리를 단순화할 수 있습니다.

현재 구현은 refreshTokens가 null일 때 새 ArrayList를 초기화한 후 바로 반환합니다(129-130행). null인 경우 초기화 없이 바로 반환하거나, null이 아닐 때만 clear를 호출하는 것이 더 명확합니다.

🔎 단순화 제안
 public void removeAllRefreshTokens() {
-    if (this.refreshTokens == null) {
-        this.refreshTokens = new ArrayList<>();
-        return;
-    }
-    this.refreshTokens.clear();
+    if (this.refreshTokens != null) {
+        this.refreshTokens.clear();
+    }
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 616dcbb and 91fbc3d.

📒 Files selected for processing (3)
  • backend/src/main/java/moadong/user/entity/User.java
  • backend/src/main/java/moadong/user/repository/UserRepository.java
  • backend/src/main/java/moadong/user/service/UserCommandService.java
🔇 Additional comments (9)
backend/src/main/java/moadong/user/repository/UserRepository.java (1)

12-12: 메서드 이름 변경이 적절합니다.

refreshTokens 컬렉션 필드와 일치하도록 메서드 이름이 올바르게 변경되었습니다. Spring Data MongoDB가 중첩 필드 쿼리를 정상적으로 처리할 것입니다.

backend/src/main/java/moadong/user/service/UserCommandService.java (5)

79-80: 로그인 시 토큰 추가 로직이 올바릅니다.

리프레시 토큰을 컬렉션에 추가하는 방식으로 다중 기기 로그인을 지원하도록 변경되었습니다.


88-92: 로그아웃 로직이 적절합니다.

특정 리프레시 토큰만 제거하여 다른 기기의 세션에 영향을 주지 않도록 구현되었습니다.


123-124: 토큰 교체 로직이 적절합니다.

사용된 리프레시 토큰을 새로운 토큰으로 교체하여 토큰 재사용을 방지합니다.


148-155: 프로필 업데이트 시 모든 토큰을 초기화하는 것은 적절한 보안 조치입니다.

사용자 프로필이 변경되면 모든 기기에서 재로그인을 요구하여 보안을 강화합니다.


169-169: 비밀번호 재설정 시 모든 토큰 무효화는 보안 모범 사례입니다.

비밀번호가 변경되면 모든 세션을 무효화하여 보안을 강화합니다.

backend/src/main/java/moadong/user/entity/User.java (3)

58-60: 리프레시 토큰 컬렉션 필드 선언이 적절합니다.

@Builder.Default를 사용하여 빈 리스트로 초기화하고, MongoDB 필드 매핑을 명시적으로 지정했습니다.


100-105: 토큰 추가 메서드가 안전하게 구현되었습니다.

null 체크는 @Builder.Default로 초기화되어 있어 불필요해 보일 수 있지만, 레거시 데이터나 역직렬화 시나리오에서 방어적 코딩으로 작동합니다.


120-125: 토큰 제거 메서드가 깔끔하게 구현되었습니다.

removeIf를 사용하여 간결하고 읽기 쉬운 코드를 작성했습니다.

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

refreshtoken 추가할때 레이스컨디션 이슈는 발생할꺼같은데 크리티컬하진 않은것 같습니다~ 리뷰하다 든생각인데 리프레시 토큰 리스트 길이 제한은 나중에 추가하는게 좋아보여요! 수고하셨습니다

@lepitaaar lepitaaar merged commit bfa1fc3 into develop/be Dec 26, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Dec 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💾 BE Backend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants