Skip to content

Conversation

@Gyuhyeok99
Copy link
Contributor

관련 이슈

작업 내용

채팅 기능 테스트를 위해 멘토링 api를 bruno에서 호출하는데 계속 접근권한이 없다고 호출이 안되고 있었습니다...
뭔가 하고 봤더니 SiteUser에서 long으로 받도록 수정이 되어서 RequiredArgsConstructor가 동작하지 않고있었습니다!
우선 급하게 동작하도록 수정해놨고 시간나면 다시 손좀 보겠습니다 ㅎㅎ..

특이 사항

리뷰 요구사항 (선택)

@Gyuhyeok99 Gyuhyeok99 self-assigned this Jul 27, 2025
@Gyuhyeok99 Gyuhyeok99 added the 버그 Something isn't working label Jul 27, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 27, 2025

Walkthrough

  1. RoleAuthorizationAspect 리팩토링

    • 기존에는 메서드 인자에서 직접 SiteUser 객체를 찾았으나, 이제는 @Authorizeduser 어노테이션이 붙은 user ID를 리플렉션으로 추출합니다.
    • user ID가 없으면 ACCESS_DENIED 예외를 던지고, 있으면 SiteUserRepository로 DB에서 SiteUser 엔티티를 조회합니다.
    • 사용자가 없으면 USER_NOT_FOUND 예외를 던집니다.
    • 역할 검증 로직은 validateUserRole 메서드로 분리되어, 허용된 역할에 해당하지 않으면 ACCESS_DENIED 예외를 발생시킵니다.
    • 검증이 모두 통과하면 join point를 진행합니다.
  2. RoleAuthorizationAspectTest 테스트 코드 변경

    • 테스트 대상 서비스 메서드들이 SiteUser 객체 대신 @Authorizeduser가 붙은 long 타입 user ID를 받도록 변경되었습니다.
    • 테스트 로직은 동일하지만, 입력값이 user 객체에서 user ID로 바뀌었습니다.
    • @Authorizeduser 어노테이션 import가 추가되었습니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20분

  • 복수의 메서드 시그니처 변경과 리플렉션, 예외 처리, 테스트 코드 전반 수정이 포함되어 있습니다.
  • 검토 시 역할 검증 흐름, 리플렉션 기반 파라미터 추출, 예외 처리, 테스트 시나리오 적합성 등을 꼼꼼히 확인해야 합니다.

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 generate unit tests to generate unit tests for 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.

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

🧹 Nitpick comments (4)
src/main/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspect.java (4)

28-28: TODO 주석 관련 제안

"추후 개선 필요"라는 TODO가 있는데, 구체적으로 어떤 부분의 개선이 필요한지 명시하면 좋겠습니다.

예시:

-    // todo: 추후 개선 필요
+    // TODO: 리플렉션 사용 대신 Spring의 HandlerMethodArgumentResolver 활용하여 성능 개선 필요

38-39: 성능 최적화 고려사항

매 요청마다 DB 조회가 발생하는 구조입니다. 다음과 같은 최적화를 고려해보세요:

  1. 캐싱 도입: 자주 접근하는 사용자 정보를 캐싱
  2. 세션 활용: 이미 인증된 사용자 정보를 세션에서 가져오기
@Cacheable(value = "users", key = "#siteUserId")
public SiteUser findByIdWithCache(Long siteUserId) {
    return siteUserRepository.findById(siteUserId)
            .orElseThrow(() -> new CustomException(USER_NOT_FOUND));
}

54-58: 타입 체크 로직 개선 제안

현재 Long 객체와 primitive long 타입을 별도로 체크하고 있는데, 실제로는 auto-boxing으로 인해 중복된 체크입니다:

-                if (arg instanceof Long) {
-                    return (Long) arg;
-                } else if (parameters[i].getType() == long.class) {
-                    return (Long) arg;
-                }
+                if (arg instanceof Long || parameters[i].getType() == long.class) {
+                    return (Long) arg;
+                }

65-65: 컬렉션 변환 최적화

Arrays.asList()는 매번 새로운 List를 생성합니다. Stream API나 Set을 사용하면 더 효율적입니다:

-        boolean hasAccess = Arrays.asList(allowedRoles).contains(siteUser.getRole());
+        boolean hasAccess = Arrays.stream(allowedRoles).anyMatch(role -> role == siteUser.getRole());
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 80985c0 and 50b9e51.

📒 Files selected for processing (2)
  • src/main/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspect.java (1 hunks)
  • src/test/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspectTest.java (5 hunks)
🔇 Additional comments (2)
src/test/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspectTest.java (2)

8-8: 테스트에 필요한 import 추가 확인

@AuthorizedUser 어노테이션 사용을 위한 import가 적절히 추가되었습니다.


88-99: TestService 메소드 시그니처 변경 확인

변경 사항:

  1. 파라미터 타입 변경: SiteUser@AuthorizedUser long siteUserId
  2. 일관된 네이밍: 모든 메소드에서 siteUserId로 파라미터명 통일

테스트 서비스 메소드들이 실제 구현과 동일한 방식으로 수정되어 적절합니다.

Comment on lines 24 to +44
public class RoleAuthorizationAspect {

// todo: 추후 siteUserId로 파라미터 변경 시 수정 필요
private final SiteUserRepository siteUserRepository;

// todo: 추후 개선 필요
@Around("@annotation(requireRoleAccess)")
public Object checkRoleAccess(ProceedingJoinPoint joinPoint, RequireRoleAccess requireRoleAccess) throws Throwable {
SiteUser siteUser = null;
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof SiteUser) {
siteUser = (SiteUser) arg;
break;
}
}
if (siteUser == null) {

Long siteUserId = extractAuthorizedUserId(joinPoint);

if (siteUserId == null) {
throw new CustomException(ACCESS_DENIED);
}
Role[] allowedRoles = requireRoleAccess.roles();

SiteUser siteUser = siteUserRepository.findById(siteUserId)
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));

validateUserRole(siteUser, requireRoleAccess.roles());

return joinPoint.proceed();
}
Copy link

@coderabbitai coderabbitai bot Jul 27, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

아키텍처 및 보안 고려사항

현재 구현의 주요 변경사항과 고려사항:

  1. 보안 측면

    • 사용자 ID 기반 인증으로 변경되어 ID 조작 가능성 검토 필요
    • @AuthorizedUser 어노테이션이 붙은 파라미터가 실제로 인증된 사용자의 ID인지 검증 필요
  2. 성능 측면

    • 리플렉션 사용으로 인한 오버헤드
    • 매 요청마다 DB 조회 발생
  3. 개선 제안

    • Spring Security의 @AuthenticationPrincipal과 유사한 방식으로 HandlerMethodArgumentResolver 활용
    • 인증된 사용자 정보를 SecurityContext에서 직접 가져오는 방식 고려

이러한 점들이 PR 설명에서 언급된 "임시 수정"의 이유인 것으로 보입니다.


🏁 Script executed:

#!/bin/bash
# @AuthorizedUser 어노테이션의 실제 구현과 사용처 확인
echo "=== @AuthorizedUser 어노테이션 구현 확인 ==="
fd -e java "AuthorizedUser.java" --exec cat {}

echo -e "\n=== @AuthorizedUser 사용처 확인 ==="
rg "@AuthorizedUser" -A 3 -B 1

Length of output: 33412


🏁 Script executed:

#!/bin/bash
# Extract implementation of extractAuthorizedUserId
echo "=== extractAuthorizedUserId 정의 위치 ==="
rg -n "extractAuthorizedUserId" -n src/main/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspect.java

echo -e "\n=== extractAuthorizedUserId 메소드 전체 내용 ==="
ast-grep --pattern $'public class RoleAuthorizationAspect {
  $$$
  ?checkRoleAccess($$$)
  $$$
  private Long extractAuthorizedUserId($_) {
    $$$
  }
}' -r src/main/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspect.java

Length of output: 694


아키텍처 및 보안 고려사항

  1. 보안 측면

    • 사용자 ID 기반 인증 방식으로 변경되어 ID 변조 공격 가능성이 존재합니다.
    • extractAuthorizedUserIdProceedingJoinPoint.getArgs()로 인자를 읽어오기 때문에 무결성 검사를 반드시 강화해야 합니다.
  2. 성능 측면

    • Aspect 실행 시마다 SiteUserRepository.findById로 DB 조회가 이루어져 응답 지연이 발생할 수 있습니다.
    • 리플렉션 기반 인자 추출 로직이 반복 호출될 때 오버헤드가 큽니다.
  3. 아키텍처 측면

    • 인가 로직이 Aspect와 데이터 계층까지 결합되어 결합도가 높습니다.
    • HandlerMethodArgumentResolverSecurityContextHolder 기반의 표준 Spring Security 패턴을 적용해 책임 분리를 검토하세요.

장기적으로는 위 세 가지를 개선하여 안정성·성능·가독성을 모두 높일 수 있습니다.

🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/security/aspect/RoleAuthorizationAspect.java
around lines 24 to 44, the current approach extracts user ID from method
arguments and queries the database on each aspect invocation, causing security
risks, performance overhead, and tight coupling. To fix this, refactor the
authorization logic to use Spring Security's SecurityContextHolder to obtain the
authenticated user securely, avoid direct database calls in the aspect by
delegating role validation to a dedicated service or component, and consider
using HandlerMethodArgumentResolver for argument resolution. This will improve
security by preventing ID tampering, reduce DB query overhead, and separate
concerns for better maintainability.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Aspect 실행 시마다 SiteUserRepository.findById로 DB 조회가 이루어져 응답 지연이 발생할 수 있습니다.

흠~ 이 말은 일리가 있긴 하네요.
그런데 이 PR은 수습이 목표이고, 디스코드에 논의한대로 PreAuthorize 어노테이션을 사용하면
레포지토리가 아니라 security context 에서 사용자 정보를 가져오니 DB 조회가 없을것입니다~

Copy link

Choose a reason for hiding this comment

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

@nayonsoso 맞습니다! 임시 수습 목적이라면 현재 접근법이 합리적이네요.

말씀하신 대로 @PreAuthorize를 사용하면 SecurityContext에서 인증된 사용자 정보를 직접 가져와서 DB 조회 없이 권한 검사가 가능합니다. 이는 제가 앞서 제안한 SecurityContextHolder 활용 방안과 정확히 일치하는 방향입니다.

현재 구현 → @PreAuthorize 마이그레이션은 아키텍처적으로 올바른 선택입니다:

  1. 성능: DB 조회 제거
  2. 보안: Spring Security 표준 방식으로 ID 변조 위험 해결
  3. 유지보수성: 프레임워크 표준 패턴 활용

임시 수습으로서는 충분히 동작할 것 같습니다! 👍


🧠 Learnings used
Learnt from: whqtker
PR: solid-connection/solid-connect-server#408
File: src/main/java/com/example/solidconnection/chat/service/ChatService.java:46-54
Timestamp: 2025-07-28T03:14:33.849Z
Learning: 페치 조인을 사용한 N+1 문제 해결에 대해 사용자 whqtker는 JPQL 쿼리 접근법을 선호하며, SELECT 쿼리의 경우 영속성 컨텍스트 간 불일치 문제를 고려하지 않아도 된다고 인식하고 있습니다.

Copy link
Collaborator

@nayonsoso nayonsoso left a comment

Choose a reason for hiding this comment

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

확인했습니다!

Copy link
Member

@whqtker whqtker left a comment

Choose a reason for hiding this comment

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

확인했습니다 !

@Gyuhyeok99 Gyuhyeok99 merged commit 0c91030 into solid-connection:develop Jul 29, 2025
2 checks passed
@Gyuhyeok99 Gyuhyeok99 deleted the fix/409-role-auth-long-param branch August 9, 2025 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

버그 Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: RoleAuthorizationAspect 동작 안하는 버그 수정

4 participants