feat/#47: 코디북 및 코디 CRUD 기능 구현#48
Conversation
|
|
✅ 테스트 결과: 모든 테스트 통과
|
jychoi0831
left a comment
There was a problem hiding this comment.
현재 head commit 58b22cc 기준으로 확인했습니다.
P1: /api/v1/**를 공개 경로로 열어 인증 API 전체가 우회됩니다
src/main/java/com/closetnangam/be/global/config/SecurityConfig.java:35부터 PUBLIC_URLS에 /api/v1/**가 추가되어 있고, SecurityConfig.java:50에서 이 목록을 모두 permitAll()로 처리합니다. 이 패턴은 새 코디북 API만이 아니라 /api/v1 아래의 옷장, 옷, 이미지, 구매 캡처 등 기존 인증 API 전체를 JWT 없이 컨트롤러까지 통과시킵니다.
영향:
인증되지 않은 요청도 Spring Security에서 먼저 차단되지 않습니다. 이번 PR의 OutfitController.java:31부터 OutfitController.java:60처럼 컨트롤러 내부에서 SecurityUtils.getCurrentUserId()를 호출하는 엔드포인트는 토큰이 없을 때 IllegalStateException("인증 정보를 찾을 수 없습니다.")로 실패해 401/403 대신 서버 예외 흐름이 됩니다. 더 큰 문제는 기존 /api/v1 엔드포인트 중 컨트롤러에서 별도 소유권 검증을 빠뜨린 경로가 있으면 그대로 공개 API가 되어 사용자 데이터 접근/변경으로 이어질 수 있다는 점입니다.
해결 방향:
/api/v1/**는 PUBLIC_URLS에서 제거하고, 정말 공개해야 하는 API만 개별 경로로 명시해야 합니다. 코디북 API는 인증이 필요한 사용자 리소스이므로 Security 필터에서 JWT 검증이 먼저 동작하게 두고, unauthenticated 요청이 401/403으로 떨어지는 테스트도 함께 추가하는 편이 안전합니다.
P2: 코디 생성 요청 길이 검증이 DB 컬럼 길이보다 느슨해 저장 단계에서 실패할 수 있습니다
src/main/java/com/closetnangam/be/domain/outfit/dto/request/OutfitCreateRequest.java:13부터 OutfitCreateRequest.java:26까지는 title, thumbnailUrl, situation, season에 @NotBlank만 적용합니다. 그런데 엔티티는 Outfit.java:33의 title을 100자, Outfit.java:39의 thumbnailUrl을 500자, Outfit.java:42와 Outfit.java:45의 situation/season을 50자로 제한합니다.
영향:
예를 들어 200자 title이나 80자 season은 Bean Validation을 통과한 뒤 JPA flush/DB constraint 단계에서 실패합니다. 클라이언트 입장에서는 입력 오류가 400으로 안정적으로 반환되지 않고, DB 예외 기반 500 응답이나 데이터베이스별 잘림 동작에 의존하게 됩니다.
해결 방향:
요청 DTO에 엔티티 컬럼과 같은 @Size(max = 100), @Size(max = 500), @Size(max = 50) 제약을 추가해 컨트롤러 진입 시점에 검증되게 해 주세요. thumbnailUrl은 필요하다면 URL 형식 검증도 함께 고려할 수 있습니다.
검증:
git diff --check origin/develop...HEAD: 통과git merge-tree --write-tree origin/develop origin/feat/#47: 통과./gradlew compileJava --offline: 성공./gradlew test --offline: 성공gh pr view --json mergeable:MERGEABLE
본 리뷰는 Codex를 사용해 작성했습니다.
|
|
✅ 테스트 결과: 모든 테스트 통과
|
jychoi0831
left a comment
There was a problem hiding this comment.
현재 head commit c30b2dc 기준으로 확인했습니다.
이전 리뷰의 /api/v1/** 전체 공개 문제는 범위가 줄었고, OutfitCreateRequest 길이 검증도 추가된 것을 확인했습니다. 다만 아래 blocker가 여전히 남아 있습니다.
P1: 로그인 사용자 리소스인 코디북 API가 여전히 공개 경로로 열려 있습니다
src/main/java/com/closetnangam/be/global/config/SecurityConfig.java:35부터 PUBLIC_URLS에 /api/v1/outfit-books/**가 포함되어 있고, SecurityConfig.java:50에서 이 목록을 permitAll()로 처리합니다. 그런데 새 코디북 컨트롤러는 OutfitController.java:31, OutfitController.java:39, OutfitController.java:46, OutfitController.java:53의 모든 엔드포인트에서 현재 로그인한 사용자 기준으로 동작하며, 실제로 OutfitController.java:33, OutfitController.java:41, OutfitController.java:48, OutfitController.java:58에서 SecurityUtils.getCurrentUserId()를 호출합니다.
영향:
토큰이 없는 요청도 Spring Security에서 401/403으로 먼저 차단되지 않고 컨트롤러까지 도달합니다. 이 경우 SecurityUtils.getCurrentUserId()는 인증 principal이 없거나 Long이 아니면 IllegalStateException("인증 정보를 찾을 수 없습니다.")를 던지므로, 인증 실패가 정상적인 보안 응답이 아니라 서버 예외 흐름으로 처리될 수 있습니다. 더 근본적으로 코디북은 "현재 로그인한 사용자의" 리소스이므로 공개 URL 목록에 들어가면 안 됩니다.
해결 방향:
/api/v1/outfit-books/**를 PUBLIC_URLS에서 제거하고 .anyRequest().authenticated() 경로로 두어 JWT 필터/인증 실패 처리가 먼저 동작하게 해 주세요. 추가로 토큰 없이 GET /api/v1/outfit-books와 POST /api/v1/outfit-books 호출 시 401/403이 반환되는 보안 테스트가 있으면 같은 회귀를 막을 수 있습니다.
검증:
git diff --check origin/develop...HEAD: 통과git merge-tree --write-tree origin/develop origin/feat/#47: 통과./gradlew compileJava --offline: 성공./gradlew test --offline: 성공gh pr view --json mergeable:MERGEABLE
본 리뷰는 Codex를 사용해 작성했습니다.
|
|
✅ 테스트 결과: 모든 테스트 통과
|
jychoi0831
left a comment
There was a problem hiding this comment.
현재 head commit ec33924 기준으로 확인했습니다.
추가 merge-blocking finding은 발견하지 못했습니다. 이전 리뷰의 코디북 API 공개 경로 문제는 /api/v1/outfit-books/**가 PUBLIC_URLS에서 제거되어 해결됐고, OutfitCreateRequest 길이 검증도 추가된 것을 확인했습니다.
검증:
git diff --check origin/develop...HEAD: 통과git merge-tree --write-tree origin/develop origin/feat/#47: 통과./gradlew compileJava --offline: 성공./gradlew test --offline: 성공gh pr view --json mergeable:MERGEABLE
잔여 리스크 또는 테스트 보강 권장:
SecurityConfig의 공개 경로가/api/v1/auth/**로 넓어졌습니다. 현재는 local 프로파일의 mock-token만 해당하지만, 이후/api/v1/auth아래 인증 필요 API가 추가되면 의도치 않게 공개될 수 있으니 가능하면 필요한 엔드포인트만 명시하는 편이 안전합니다.- 토큰 없이
GET/POST /api/v1/outfit-books가 401로 떨어지고, 인증된 사용자는 본인 코디북만 접근 가능한지 보안 회귀 테스트를 추가하면 이번 이슈 재발을 막기 좋습니다. OutfitCreateRequest에 리뷰 반영 과정의 대화형 주석이 남아 있어 머지 전 정리하면 코드 품질이 더 깔끔합니다.
본 리뷰는 Codex를 사용해 작성했습니다.
📌 관련 이슈
Closes #47
🛠️ 작업 내용
✅ 변경 사항
🔍 테스트 내용
📷 스크린샷 (선택사항)
💬 리뷰어에게
📋 PR 체크리스트
develop브랜치를 base로 설정했나요?