[feat] 인증 블록 구현 (회원가입/로그인/JWT/역할부여) - #13
Conversation
- roles(USER/ADMIN/DOCUMENT_MANAGER), departments(개발/인사/재무), 최초 ADMIN 계정 seed 추가 - @operation description 필수화 및 서비스 log.error 규칙 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 활성 부서 목록 반환, 인증 불필요 - 회원가입 화면에서 부서 선택 드롭다운용 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 이메일 중복 확인, 부서 활성 확인, BCrypt 해시 후 저장 - 가입 시 USER role 자동 부여 - 인증 관련 ErrorCode 추가, SecurityConfig PasswordEncoder 빈 등록 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- jjwt 0.12.6 의존성 추가, JWT secret/expiration 환경변수화 - JwtProvider (HS256 토큰 생성/검증), JwtAuthenticationFilter 구현 - 로그인 시 accessToken 발급, SecurityConfig stateless 세션으로 전환 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- @currentuser 어노테이션 및 CurrentUserArgumentResolver 구현 - role 승격 즉시 반영을 위해 JWT payload 미사용, DB 직접 조회 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ADMIN만 접근 가능, SecurityConfig에서 /admin/** URL 레벨 인가 처리 - 중복 부여 방지, assignedBy에 ADMIN 기록 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough회원가입·로그인과 JWT 인증을 추가하고, 현재 사용자·활성 부서 조회 및 관리자 역할 부여 API를 구현했습니다. 보안 설정, 요청·응답 DTO, 저장소, 예외 코드, 초기 역할·부서·관리자 시드 데이터도 함께 추가되었습니다. Changes인증 및 사용자 관리
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant AuthController
participant AuthCommandService
participant JwtProvider
participant JwtAuthenticationFilter
participant CurrentUserArgumentResolver
Client->>AuthController: 회원가입 또는 로그인 요청
AuthController->>AuthCommandService: 요청 전달
AuthCommandService->>JwtProvider: 로그인 JWT 생성
JwtProvider-->>AuthCommandService: access token 반환
AuthCommandService-->>Client: 인증 응답 반환
Client->>JwtAuthenticationFilter: Bearer 토큰 요청
JwtAuthenticationFilter->>JwtProvider: 토큰 검증 및 클레임 조회
JwtAuthenticationFilter->>CurrentUserArgumentResolver: SecurityContext 인증 정보 제공
CurrentUserArgumentResolver-->>AuthController: 현재 userId 주입
AuthController-->>Client: 현재 사용자 정보 반환
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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.
🧹 Nitpick comments (2)
src/main/java/com/opensource/docgrid/domain/auth/jwt/JwtAuthenticationFilter.java (1)
29-33: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueJWT 중복 파싱 제거 권장
현재 토큰이 유효한 경우
jwtProvider.validateToken()에서 한 번, 이후getUserId(),getEmail(),getRoles()에서 각각getClaims()를 호출하여 총 네 번 토큰을 파싱(검증)하게 됩니다. 암호학적 서명 검증이 반복되므로, 성능 최적화를 위해 한 번 파싱한Claims객체를 반환하여 재사용하는 방식을 권장합니다.♻️ 리팩토링 제안
예를 들어,
JwtProvider에서Claims를 반환하는getClaimsIfValid(String token)와 같은 메서드를 만들고 필터에서는 다음과 같이 사용할 수 있습니다:// JwtAuthenticationFilter.java Claims claims = jwtProvider.getClaimsIfValid(token); if (claims != null) { Long userId = claims.get("userId", Long.class); String email = claims.getSubject(); List<String> roles = claims.get("roles", List.class); // ... }🤖 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/opensource/docgrid/domain/auth/jwt/JwtAuthenticationFilter.java` around lines 29 - 33, Update JwtAuthenticationFilter to parse and validate the token once through a JwtProvider method such as getClaimsIfValid, then reuse the returned Claims for userId, email, and roles instead of calling validateToken and the individual JwtProvider getters. Add or adapt the JwtProvider API as needed while preserving the existing invalid-token behavior.src/main/java/com/opensource/docgrid/domain/user/repository/UserRoleRepository.java (1)
16-17: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winSpring Data JPA의 기본 메서드 이름 규칙을 활용해 쿼리를 최적화하세요.
@Query를 사용해COUNT로 존재 여부를 확인하면 조건에 맞는 모든 레코드를 세게 되어 성능에 불리할 수 있습니다. Spring Data JPA가 제공하는existsBy파생 쿼리를 사용하면 데이터베이스 수준에서LIMIT 1최적화가 이루어져 더 효율적입니다.♻️ 제안하는 수정
- `@Query`("SELECT COUNT(ur) > 0 FROM UserRole ur WHERE ur.user.id = :userId AND ur.role.code = :roleCode") - boolean existsByUserIdAndRoleCode(`@Param`("userId") Long userId, `@Param`("roleCode") String roleCode); + boolean existsByUserIdAndRoleCode(Long userId, String roleCode);🤖 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/opensource/docgrid/domain/user/repository/UserRoleRepository.java` around lines 16 - 17, Update UserRoleRepository.existsByUserIdAndRoleCode to remove the custom `@Query` and rely on Spring Data JPA’s derived existsBy method naming, preserving the existing userId and roleCode filtering and boolean return contract.
🤖 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.
Nitpick comments:
In
`@src/main/java/com/opensource/docgrid/domain/auth/jwt/JwtAuthenticationFilter.java`:
- Around line 29-33: Update JwtAuthenticationFilter to parse and validate the
token once through a JwtProvider method such as getClaimsIfValid, then reuse the
returned Claims for userId, email, and roles instead of calling validateToken
and the individual JwtProvider getters. Add or adapt the JwtProvider API as
needed while preserving the existing invalid-token behavior.
In
`@src/main/java/com/opensource/docgrid/domain/user/repository/UserRoleRepository.java`:
- Around line 16-17: Update UserRoleRepository.existsByUserIdAndRoleCode to
remove the custom `@Query` and rely on Spring Data JPA’s derived existsBy method
naming, preserving the existing userId and roleCode filtering and boolean return
contract.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 582dc022-d14f-4423-8754-214c33b91460
📒 Files selected for processing (30)
.claude/rules/code_style.mdbuild.gradlesrc/main/java/com/opensource/docgrid/domain/auth/annotation/CurrentUser.javasrc/main/java/com/opensource/docgrid/domain/auth/controller/AuthController.javasrc/main/java/com/opensource/docgrid/domain/auth/dto/request/LoginRequest.javasrc/main/java/com/opensource/docgrid/domain/auth/dto/request/SignupRequest.javasrc/main/java/com/opensource/docgrid/domain/auth/dto/response/LoginResponse.javasrc/main/java/com/opensource/docgrid/domain/auth/dto/response/MeResponse.javasrc/main/java/com/opensource/docgrid/domain/auth/dto/response/SignupResponse.javasrc/main/java/com/opensource/docgrid/domain/auth/jwt/JwtAuthenticationFilter.javasrc/main/java/com/opensource/docgrid/domain/auth/jwt/JwtProvider.javasrc/main/java/com/opensource/docgrid/domain/auth/resolver/CurrentUserArgumentResolver.javasrc/main/java/com/opensource/docgrid/domain/auth/service/command/AuthCommandService.javasrc/main/java/com/opensource/docgrid/domain/auth/service/query/AuthQueryService.javasrc/main/java/com/opensource/docgrid/domain/user/controller/AdminUserController.javasrc/main/java/com/opensource/docgrid/domain/user/controller/DepartmentController.javasrc/main/java/com/opensource/docgrid/domain/user/dto/request/AssignRoleRequest.javasrc/main/java/com/opensource/docgrid/domain/user/dto/response/DepartmentResponse.javasrc/main/java/com/opensource/docgrid/domain/user/dto/response/UserRoleResponse.javasrc/main/java/com/opensource/docgrid/domain/user/repository/DepartmentRepository.javasrc/main/java/com/opensource/docgrid/domain/user/repository/RoleRepository.javasrc/main/java/com/opensource/docgrid/domain/user/repository/UserRepository.javasrc/main/java/com/opensource/docgrid/domain/user/repository/UserRoleRepository.javasrc/main/java/com/opensource/docgrid/domain/user/service/command/UserRoleCommandService.javasrc/main/java/com/opensource/docgrid/domain/user/service/query/DepartmentQueryService.javasrc/main/java/com/opensource/docgrid/global/config/SecurityConfig.javasrc/main/java/com/opensource/docgrid/global/config/WebMvcConfig.javasrc/main/java/com/opensource/docgrid/global/exception/ErrorCode.javasrc/main/resources/application.ymlsrc/main/resources/db/migration/V28__seed_roles_departments_admin.sql
- JwtProvider.getClaimsIfValid()로 토큰 파싱 1회로 통합 (기존 4회 → 1회) - UserRoleRepository.existsByUserIdAndRoleCode @query 제거, JPA 파생 쿼리로 대체 (DB LIMIT 1 최적화) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔍 작업 내용
✨ 상세 설명
인증 블록 전체 구현
구현된 API
POST /auth/signup— 회원가입, 가입 시 USER role 자동 부여POST /auth/login— 로그인, JWT(HS256, 1시간 만료) 발급GET /auth/me— 내 정보 조회 (DB 직접 조회, role 승격 즉시 반영)POST /admin/users/{userId}/roles— 역할 부여 (ADMIN 전용)GET /departments— 활성 부서 목록 조회 (인증 불필요)주요 설계 결정
JwtAuthenticationFilter로 매 요청 검증/me는 토큰 payload 미사용 → DB 재조회로 역할 승격 즉시 반영/admin/**URL 레벨 인가 처리 (SecurityConfig)@CurrentUser커스텀 어노테이션으로 컨트롤러에서 userId 주입도메인 구조
domain/auth/— 인증 흐름 전담 (로그인/회원가입/JWT)domain/user/— 유저 엔티티/레포지토리, 역할 관리🛠 추후 리팩토링 및 고도화 계획
AuthCommandService단위 테스트 추가JwtProvider단위 테스트 추가📸 스크린샷 (선택)
로그인




부서 조회
회원가입
권한 부여
💬 리뷰 요구사항
JwtAuthenticationFilter에서authentication.setDetails(userId)로 userId를 넘기는 방식이 적절한지/admin/**URL 레벨 인가 vs@PreAuthorize메서드 레벨 인가 선택에 대한 의견Summary by CodeRabbit