1616import com .backend .global .response .ApiResponse ;
1717import jakarta .servlet .http .HttpServletRequest ;
1818import lombok .RequiredArgsConstructor ;
19+ import lombok .extern .slf4j .Slf4j ;
1920import org .springframework .http .ResponseEntity ;
2021import org .springframework .transaction .annotation .Transactional ;
2122import org .springframework .web .bind .annotation .*;
2425import java .util .ArrayList ;
2526import java .util .List ;
2627
28+ @ Slf4j
2729@ RestController
2830@ RequiredArgsConstructor
2931@ RequestMapping ("/api/analysis" )
@@ -84,16 +86,8 @@ public ResponseEntity<ApiResponse<HistoryResponseDto>> getAnalysisByRepositories
8486 Repositories repository = repositoryService .findById (repoId )
8587 .orElseThrow (() -> new BusinessException (ErrorCode .GITHUB_REPO_NOT_FOUND ));
8688
87- RepositoryResponse repositoryResponse = new RepositoryResponse (repository );
88-
8989 // 권한 검증
90- Long jwtUserId = jwtUtil .getUserId (httpRequest );
91- boolean isOwner = jwtUserId .equals (userId );
92- boolean isPublic = repository .isPublicRepository ();
93-
94- if (!isOwner && !isPublic ) {
95- throw new BusinessException (ErrorCode .FORBIDDEN );
96- }
90+ validateAccess (httpRequest , userId , repository );
9791
9892 // 2. 분석 결과 목록 조회 (최신순 정렬)
9993 List <AnalysisResult > analysisResults =
@@ -109,6 +103,7 @@ public ResponseEntity<ApiResponse<HistoryResponseDto>> getAnalysisByRepositories
109103 }
110104
111105 // 4. 응답 조합
106+ RepositoryResponse repositoryResponse = new RepositoryResponse (repository );
112107 HistoryResponseDto response = HistoryResponseDto .of (repositoryResponse , versions );
113108
114109 return ResponseEntity .ok (ApiResponse .success (response ));
@@ -131,14 +126,7 @@ public ResponseEntity<ApiResponse<AnalysisResultResponseDto>> getAnalysisDetail(
131126 }
132127
133128 // 권한 검증
134- Long jwtUserId = jwtUtil .getUserId (httpRequest );
135- Repositories repository = analysisResult .getRepositories ();
136- boolean isOwner = jwtUserId .equals (userId );
137- boolean isPublic = repository .isPublicRepository ();
138-
139- if (!isOwner && !isPublic ) {
140- throw new BusinessException (ErrorCode .FORBIDDEN );
141- }
129+ validateAccess (httpRequest , userId , analysisResult .getRepositories ());
142130
143131 AnalysisResultResponseDto response =
144132 new AnalysisResultResponseDto (analysisResult , analysisResult .getScore ());
@@ -203,4 +191,41 @@ public SseEmitter stream(@PathVariable Long userId,
203191
204192 return analysisProgressService .connect (userId );
205193 }
194+
195+ /**
196+ * 리포지토리 접근 권한 검증
197+ * - 공개 리포지토리: 누구나 접근 가능 (비로그인 포함)
198+ * - 비공개 리포지토리: 소유자만 접근 가능
199+ */
200+
201+ private void validateAccess (HttpServletRequest requeset , Long pathUserId , Repositories repository ) {
202+ Long jwtUserId = jwtUtil .getUserId (requeset );
203+
204+ // 1. 공개 리포지토리일 경우
205+ if (repository .isPublicRepository ()) {
206+ if (jwtUserId == null ) {
207+ log .warn ("비로그인 사용자의 공개 리포지토리 접근 시도: repoId={}" , repository .getId ());
208+ }
209+
210+ if (!jwtUserId .equals (pathUserId )) {
211+ log .warn ("다른 사용자의 공개 리포지토리 접근 시도: jwtUserId={}, pathUserId={}, repoId={}" ,
212+ jwtUserId , pathUserId , repository .getId ());
213+ }
214+ return ;
215+ }
216+
217+ // 2. 비공개 리포지토리일 경우
218+ // 2-1. 비로그인
219+ if (jwtUserId == null ) {
220+ log .warn ("비로그인 사용자의 비공개 리포지토리 접근 시도: repoId={}" , repository .getId ());
221+ throw new BusinessException (ErrorCode .FORBIDDEN );
222+ }
223+
224+ // 2-2. 다른 사용자
225+ if (!jwtUserId .equals (pathUserId )) {
226+ log .warn ("권한 없는 접근 시도: jwtUserId={}, pathUserId={}, repoId={}" ,
227+ jwtUserId , pathUserId , repository .getId ());
228+ throw new BusinessException (ErrorCode .FORBIDDEN );
229+ }
230+ }
206231}
0 commit comments