Skip to content

Conversation

@seung-in-Yoo
Copy link
Member

@seung-in-Yoo seung-in-Yoo commented Jul 18, 2025

#️⃣ 연관된 이슈

#41

📝 작업 내용

  • Refresh Token 저장 -> RDB 저장 방식으로 구현하였습니다.
  • 로그인 시 accessToken과 refreshToken을 함께 발급하고, refreshToken을 DB에 저장합니다.
  • refreshtoken 관련 엔티티를 새로 추가하였습니다.
  • accessToken 만료 시, refreshToken을 통해 새로운 accessToken/refreshToken을 재발급할수 있는 토큰 재발급 API를 구현하였습니다.
  • accessToken으로 인증 후, DB에 저장된 refreshToken 삭제하여 로그아웃 처리하는 로그아웃 API를 구현하였습니다.

📸 스크린샷

회원가입 및 토큰 발급

회원가입토큰발급성공(1)

refresh token 토큰 DB에 저장

토큰발급디비(1)

토큰 재발급

토큰재발급성공(1)

로그아웃

로그아웃성공(1)

💬 리뷰 요구사항 (선택)

  • 원래 redis를 사용하여 refresh token을 저장하고 싶었는데 aws 프리티어 사용의 한계로 DB 기반 refresh token 저장 방식으로 구현하였습니다.

Summary by CodeRabbit

  • 신규 기능

    • 리프레시 토큰 발급 및 관리 기능이 추가되었습니다. 로그인 시 액세스 토큰과 리프레시 토큰이 함께 발급됩니다.
    • 리프레시 토큰을 통한 액세스 토큰 재발급(/reissue) 및 로그아웃(/logout) API가 추가되었습니다.
  • 기타

    • 리프레시 토큰 관련 데이터가 안전하게 저장 및 관리됩니다.
    • 관련 API 엔드포인트가 인증 없이 접근 가능하도록 변경되었습니다.

@seung-in-Yoo seung-in-Yoo self-assigned this Jul 18, 2025
@seung-in-Yoo seung-in-Yoo added 💡 feature 기능 구현 및 개발 🔧 refactor 코드 리팩토링 🛠️ fix 기능 오류 및 코드 개선이 필요한 곳 수정 labels Jul 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

"""

Walkthrough

리프레시 토큰 기반의 인증 기능이 추가되었습니다. 신규 엔티티와 리포지토리로 리프레시 토큰을 관리하며, 로그인 시 액세스/리프레시 토큰을 모두 발급합니다. /reissue/logout 엔드포인트가 추가되어 토큰 재발급과 로그아웃 처리를 제공합니다. 관련 보안 설정도 갱신되었습니다.

Changes

파일/그룹 변경 요약
.../config/SecurityConfig.java /reissue, /logout 엔드포인트를 인증 없이 접근 가능하도록 보안 설정 변경
.../config/security/JwtProperties.java 리프레시 토큰 만료값 필드 및 getter/setter 추가
.../config/security/jwt/JwtTokenProvider.java 리프레시 토큰 생성 및 토큰 만료 조회 메서드 추가
.../user/controller/UserController.java /reissue, /logout API 엔드포인트 추가 및 Swagger 문서화, JwtTokenProvider 의존성 주입
.../user/dto/token/TokenResponseDto.java accessToken, refreshToken 필드로 record 확장
.../user/entity/RefreshToken.java RefreshToken JPA 엔티티 신설 (userId, token, expiry 등 포함)
.../user/repository/RefreshTokenRepository.java RefreshTokenRepository JPA 리포지토리 신설 및 사용자/토큰별 조회, 삭제 메서드 추가
.../user/service/auth/AuthService.java 로그인 시 리프레시 토큰 발급/저장, reissue 및 logout 메서드 추가, login 반환값 확장

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant UserController
    participant AuthService
    participant JwtTokenProvider
    participant RefreshTokenRepository

    Client->>UserController: POST /login (로그인 요청)
    UserController->>AuthService: login()
    AuthService->>JwtTokenProvider: generateAccessToken()
    AuthService->>JwtTokenProvider: generateRefreshToken()
    AuthService->>RefreshTokenRepository: deleteByUserId()
    AuthService->>RefreshTokenRepository: save(refreshToken)
    AuthService-->>UserController: TokenResponseDto (access+refresh)
    UserController-->>Client: 응답 (access+refresh 토큰)

    Client->>UserController: POST /reissue (refreshToken 전달)
    UserController->>AuthService: reissue(refreshToken)
    AuthService->>RefreshTokenRepository: findByToken()
    AuthService->>JwtTokenProvider: getUserId(refreshToken)
    AuthService->>JwtTokenProvider: generateAccessToken()
    AuthService-->>UserController: TokenResponseDto (access+refresh)
    UserController-->>Client: 응답 (새 access, 기존 refresh)

    Client->>UserController: POST /logout (Authorization: Bearer accessToken)
    UserController->>JwtTokenProvider: getUserId(accessToken)
    UserController->>AuthService: logout(userId)
    AuthService->>RefreshTokenRepository: deleteByUserId()
    AuthService-->>UserController: 완료
    UserController-->>Client: 성공 메시지
Loading

Possibly related PRs

Suggested labels

⚙️ chore

Suggested reviewers

  • KiSeungMin

Poem

🐰
토큰이 두 개, 깡총깡총 hop!
액세스와 리프레시, 로그인도 척척
재발급도 로그아웃도
이제는 걱정 마세요
깡총이처럼 안전하게
인증의 들판을 달려요!
🥕
"""


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f90dc79 and 7add545.

📒 Files selected for processing (5)
  • src/main/java/com/wayble/server/common/config/security/jwt/JwtTokenProvider.java (2 hunks)
  • src/main/java/com/wayble/server/user/controller/UserController.java (3 hunks)
  • src/main/java/com/wayble/server/user/entity/RefreshToken.java (1 hunks)
  • src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java (1 hunks)
  • src/main/java/com/wayble/server/user/service/auth/AuthService.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main/java/com/wayble/server/common/config/security/jwt/JwtTokenProvider.java
  • src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java
  • src/main/java/com/wayble/server/user/controller/UserController.java
  • src/main/java/com/wayble/server/user/entity/RefreshToken.java
🔇 Additional comments (3)
src/main/java/com/wayble/server/user/service/auth/AuthService.java (3)

7-7: 의존성 및 임포트가 올바르게 추가되었습니다.

리프레시 토큰 기능을 위해 필요한 엔티티, 리포지토리, 그리고 트랜잭션 어노테이션이 적절히 추가되었습니다.

Also applies to: 10-10, 12-12, 22-22


26-46: 로그인 메서드 구현이 우수합니다.

리프레시 토큰 생성 및 저장 로직이 올바르게 구현되었습니다:

  • 기존 리프레시 토큰 삭제로 토큰 중복 방지
  • 액세스 토큰과 리프레시 토큰 모두 생성
  • 만료 시간 저장으로 후속 검증 지원

79-82: 로그아웃 메서드가 올바르게 구현되었습니다.

트랜잭션 어노테이션과 함께 리프레시 토큰을 안전하게 삭제하는 간단하고 효과적인 구현입니다.

✨ 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 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.

@seung-in-Yoo seung-in-Yoo linked an issue Jul 18, 2025 that may be closed by this pull request
8 tasks
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: 5

🧹 Nitpick comments (3)
src/main/java/com/wayble/server/user/entity/RefreshToken.java (2)

24-25: 만료 시간 필드 타입 개선 제안

expiry 필드를 Long 타입으로 사용하는 것보다 LocalDateTime을 사용하는 것이 더 명확하고 안전합니다.

+import java.time.LocalDateTime;
+
 @Column(nullable = false)
-private Long expiry; // 만료 시간
+private LocalDateTime expiry; // 만료 시간

이 경우 JwtTokenProvider에서도 해당 변경사항을 반영해야 합니다.


12-26: User 엔티티와의 관계 설정 고려

현재 userId를 Long 타입으로 직접 참조하고 있는데, JPA의 @manytoone 관계를 사용하여 User 엔티티와의 관계를 명시적으로 설정하는 것을 고려해 보세요.

+@ManyToOne(fetch = FetchType.LAZY)
+@JoinColumn(name = "user_id", nullable = false, unique = true)
+private User user;
-
-@Column(nullable = false, unique = true) // 1인 1토큰
-private Long userId;

단, 현재 구조도 충분히 동작하므로 선택사항입니다.

src/main/java/com/wayble/server/user/service/auth/AuthService.java (1)

26-46: 로그인 로직이 잘 구현되었습니다.

기존 refresh token을 삭제하고 새로 생성하는 방식이 적절합니다. 다만, 동시성 문제를 완전히 방지하려면 이 메서드에도 @Transactional 어노테이션을 추가하는 것을 고려해보세요.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 73bef6e and f90dc79.

📒 Files selected for processing (8)
  • src/main/java/com/wayble/server/common/config/SecurityConfig.java (1 hunks)
  • src/main/java/com/wayble/server/common/config/security/JwtProperties.java (2 hunks)
  • src/main/java/com/wayble/server/common/config/security/jwt/JwtTokenProvider.java (2 hunks)
  • src/main/java/com/wayble/server/user/controller/UserController.java (3 hunks)
  • src/main/java/com/wayble/server/user/dto/token/TokenResponseDto.java (1 hunks)
  • src/main/java/com/wayble/server/user/entity/RefreshToken.java (1 hunks)
  • src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java (1 hunks)
  • src/main/java/com/wayble/server/user/service/auth/AuthService.java (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/java/com/wayble/server/user/entity/RefreshToken.java (1)
Learnt from: seung-in-Yoo
PR: Wayble-Project/wayble-spring#37
File: src/main/java/com/wayble/server/user/entity/User.java:61-62
Timestamp: 2025-07-13T15:08:59.288Z
Learning: Java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 import 없이 사용 가능하다.
🔇 Additional comments (8)
src/main/java/com/wayble/server/user/dto/token/TokenResponseDto.java (1)

3-3: 리프레시 토큰 필드 추가 승인

accessToken과 refreshToken을 모두 포함하는 DTO 구조로 적절하게 수정되었습니다. record 타입 사용으로 불변성과 간결성을 동시에 확보했습니다.

src/main/java/com/wayble/server/common/config/security/JwtProperties.java (2)

12-12: 리프레시 토큰 만료 시간 설정 추가 승인

리프레시 토큰의 만료 시간을 설정할 수 있는 refreshExp 필드가 적절하게 추가되었습니다.


31-33: 환경 설정에 refreshExp 프로퍼티 추가 확인 요청
JwtProperties.java에 새로 추가된 refreshExp 필드가 애플리케이션 설정 파일에 반영되어 있는지 검토해 주세요.

확인 대상 파일:

  • application.yml / application.yaml (jwt.refresh-exp: 또는 refreshExp:)
  • application.properties (jwt.refresh-exp=)

필요 시 해당 키를 추가하거나, 기본값을 문서화해 주세요.

src/main/java/com/wayble/server/user/entity/RefreshToken.java (1)

18-19: 1인 1토큰 제약조건 적절히 설정됨

userId에 unique 제약조건을 설정하여 사용자당 하나의 리프레시 토큰만 유지하도록 한 것은 보안상 적절한 설계입니다.

src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java (1)

8-12: 리포지토리 메서드 구조 적절함

필요한 CRUD 작업을 위한 메서드들이 Spring Data JPA 네이밍 컨벤션에 따라 적절히 정의되었습니다.

src/main/java/com/wayble/server/common/config/security/jwt/JwtTokenProvider.java (1)

34-41: Refresh token 생성 로직이 적절합니다.

Refresh token에는 최소한의 정보만 포함하고 role claim을 제외한 것이 보안 관점에서 좋은 선택입니다.

src/main/java/com/wayble/server/user/controller/UserController.java (1)

63-82: Token 재발급 엔드포인트가 잘 구현되었습니다.

RESTful 규칙을 잘 따르고 있으며, OpenAPI 문서화도 명확합니다.

src/main/java/com/wayble/server/user/service/auth/AuthService.java (1)

66-69: 로그아웃 구현이 깔끔합니다.

Refresh token을 삭제하여 로그아웃을 처리하는 방식이 적절합니다.

Comment on lines +39 to +40
"/api/v1/users/reissue",
"/api/v1/users/logout",
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

로그아웃 엔드포인트의 보안 설정 재검토 필요

/api/v1/users/logout 엔드포인트를 인증 없이 접근 가능하도록 설정하는 것은 보안상 위험할 수 있습니다. 로그아웃은 인증된 사용자만 수행해야 하는 작업입니다.

제안사항:

  • reissue 엔드포인트는 리프레시 토큰 검증이 필요하므로 permitAll() 유지 가능
  • logout 엔드포인트는 액세스 토큰 검증이 필요하므로 authenticated() 요구 권장
                        .requestMatchers(
                                "/api/v1/users/signup",
                                "/api/v1/users/login",
                                "/api/v1/users/reissue",
-                               "/api/v1/users/logout",
                                "/swagger-ui/**",
                                "/v3/api-docs/**"
                        ).permitAll()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"/api/v1/users/reissue",
"/api/v1/users/logout",
http
.authorizeRequests()
.requestMatchers(
"/api/v1/users/signup",
"/api/v1/users/login",
"/api/v1/users/reissue",
"/swagger-ui/**",
"/v3/api-docs/**"
).permitAll()
// all other endpoints (including /api/v1/users/logout) now require authentication
.anyRequest().authenticated();
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/common/config/SecurityConfig.java around
lines 39 to 40, the /api/v1/users/logout endpoint is currently configured to
allow access without authentication, which is a security risk. Modify the
security configuration to require authentication for the logout endpoint by
replacing permitAll() with authenticated() for this path, while keeping
permitAll() for the /api/v1/users/reissue endpoint as it requires refresh token
validation.

public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
Optional<RefreshToken> findByUserId(Long userId);
Optional<RefreshToken> findByToken(String token);
void deleteByUserId(Long userId);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

삭제 메서드에 @transactional 추가 권장

deleteByUserId 메서드는 데이터를 삭제하는 작업이므로 @transactional 어노테이션을 추가하는 것이 좋습니다.

+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
 void deleteByUserId(Long userId);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void deleteByUserId(Long userId);
import org.springframework.transaction.annotation.Transactional;
@Transactional
void deleteByUserId(Long userId);
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java
at line 11, the deleteByUserId method performs a data deletion operation and
should be annotated with @Transactional to ensure the operation is executed
within a transaction. Add the @Transactional annotation above the deleteByUserId
method declaration to properly manage the transaction scope during deletion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💡 feature 기능 구현 및 개발 🛠️ fix 기능 오류 및 코드 개선이 필요한 곳 수정 🔧 refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] JWT 기반 로그인 및 회원가입 구현

2 participants