-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] feat: 리소스 접근 권한 검증 aop 구현 #1089
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아직 꼼꼼하게 다 확인은 못했는데요,
리졸버 구현과 중복되는 로직이 존재하는 것 같아서 우선 RC 먼저 남길게요!
리졸버에서 세션을 확인하고, dto를 반환해서 컨트롤러 메서드 인자로 넘겨주고 있습니다.
근데 aop에서도 세션을 확인하는 동일한 로직을 하는 것으로 보여요. (아마 리졸버 구현 전이라 이렇게 구현했을 거라 생각해요.)
따라서 리졸버 구현이 단순하니 먼저 머지하고, JoinPoint의 LoginMember 또는 GuestReviewGroup을 직접 사용하도록 변경하면 어떨까요?
- 존재하는 세션을 확인한다. (회원 세션 or 비회원 세션)
- 존재하는 세션과 요청된 자원 id의 관계를 확인하여 검증
위 내용에 동의하면 작업하는 동안 더 세부적으로 보고있겠습니다~
저는 “세션에 저장된 정보를 가져오기 위한 resolver”와 resolver가 만들어준 LoginMember 또는 GuestReviewGroup를 직접 사용하는 aop라면, 아래와 같이 구현될거예요. @PostMapping("/v2/highlight")
@RequireReviewGroupAccess(target = "#request.reviewGroupId()”)
public ResponseEntity<Void> highlight(
@Valid @RequestBody HighlightsRequest request,
@LoginMemberSession(required = false) LoginMember loginMember,
@GuestReviewGroupSession(required = false) GuestReviewGroup guestReviewGroup
) {
highlightService.editHighlight(request);
return ResponseEntity.ok().build();
} aop 가 resolver에 종석적이라서, aop 에게 값을 전달하기 위한 용도의 인자가 생겼어요. 🙀 이들이 둘 다 세션에 접근하긴 하지만, aop와 resolver 를 같이 쓰는 곳이 없어요. @PostMapping("/v2/highlight")
@RequireReviewGroupAccess(target = "#request.reviewGroupId()”)
public ResponseEntity<Void> highlight(
@Valid @RequestBody HighlightsRequest request
) {
highlightService.editHighlight(request);
return ResponseEntity.ok().build();
} 테드는 첫번째 코드가 더 읽기 좋나요, 두번째 코드가 읽기 좋나요? |
사전에 작업 이해한 내용이 조금 달랐던 거 같네요.. 그럼 산초가 말한 것처럼 리졸버는 기존처럼 변환만 하고 aop에서 모든 인증을 다 하는 게 깔끔하네요~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
산초우 aop 구현 잘했네요 👍👍
다만 몇 가지 포인트에서 문제 될 수 있는 부분이나 더 좋은 의견과 함께 리뷰 남깁니다!
private final ReviewRepository reviewRepository; | ||
private final ReviewGroupRepository reviewGroupRepository; | ||
|
||
@Transactional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aspect 내부에서 트랜잭션을 사용하는 이유가 무엇인가요?
이 안에서 트랜잭션을 시작하면, 비즈니스 로직이 수행되는 서비스 계층의 트랜잭션 경계와 중첩 되어서 예상치 못한 작동이 일어날 수 있다고 생각하는데요. 또한 컨트롤러 메서드가 트랜잭션 안에서 실행되어야 하는 이유도 모르겠어요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DB조회하는 동작이라 습관적으로 붙였던 것 같습니다😞
없애는게 맞겠네요!
private boolean isMemberAuthorized(Review review, HttpSession session) { | ||
GitHubMember gitHubMember = sessionManager.getGitHubMember(session); | ||
if (gitHubMember == null) { | ||
return false; | ||
} | ||
|
||
boolean isReviewGroupCreator = reviewGroupRepository.findAllByMemberId(gitHubMember.getMemberId()) | ||
.stream() | ||
.map(ReviewGroup::getId) | ||
.anyMatch(id -> id == review.getReviewGroupId()); | ||
boolean isReviewAuthor = review.getMemberId() != null && review.getMemberId() == gitHubMember.getMemberId(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
회원이 등록한 모든 그룹을 찾고 반복하면서 리뷰의 그룹 아이디와 일치하는 그룹을 찾고 있어서 비효율적으로 보여요.
리뷰에 있는 그룹 아이디로 해당 그룹만 찾고 그룹에 있는 회원 아이디와 gitHubMember.getMemberId()
만 비교하면 간단할 거 같다는 생각인데, 혹시 이렇게 한 이유가 있을까요?
or reviewGroupRepository.existsByMemberIdAndReviewGroupId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
ReviewGroup reviewGroup = reviewGroupRepository.findByReviewRequestCode(reviewRequestCode) | ||
.orElseThrow(() -> new ReviewGroupNotFoundByReviewRequestCodeException(reviewRequestCode)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 예외를 여기서 던지는 것이 맞을지 생각이 듭니다요..
예외 메세지가 클라이언트에게 전달이 될텐데, 클라이언트 입장에서는 세션을 통해 던져진 ReviewRequestCode라서, 사실 세션을 사용한지도 모를텐데 뜬금없는 메세지를 받게 될 것 같아요. 그리고 세션에 저장된 코드로 도메인 객체를 찾을 수 없다는 건 NotFound가 아닌 서버 에러로 봐야 한다고 생각합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그렇네요, ReviewRequestCode 때문이라는 메세지를 담은
"ReviewGroupNotFoundByReviewRequestCodeException"는 변경해야겠네요😅
private final SessionManager sessionManager; | ||
private final ReviewGroupRepository reviewGroupRepository; | ||
|
||
@Transactional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기 트랜잭션도 위에서 했던 의견과 동일합니다!
58ed576
to
d8f2ca4
Compare
Deploying 2024-review-me-release with
|
Latest commit: |
de1ff1c
|
Status: | ✅ Deploy successful! |
Preview URL: | https://c6652008.2024-review-me-release.pages.dev |
Branch Preview URL: | https://be-feat-1085-resource-author.2024-review-me-release.pages.dev |
Deploying 2024-review-me-develop with
|
Latest commit: |
de1ff1c
|
Status: | ✅ Deploy successful! |
Preview URL: | https://1c986b6f.2024-review-me-develop.pages.dev |
Branch Preview URL: | https://be-feat-1085-resource-author.2024-review-me-develop.pages.dev |
✍️ 추가된 부분
|
- 세션과 권한의 책임으로 바뀌었으므로 삭제한다.
- 더 중요한 검증이 먼저 오도록
- 서비스 코드에 aop 를 붙이지 않고, 컨트롤러에 붙임에 따라서 테스트 설정을 원복한다.
- 세션에 저장된 정보에 해당하는게 DB에 없다는 의미 전달
- global.authorization -> security.aspects
281a992
to
de1ff1c
Compare
🚀 어떤 기능을 구현했나요 ?
🔥 어떻게 해결했나요 ?
그런데 테드가 구현한 resolver 를 보고, 권한 검증도 컨트롤러에서 하는게 좋겠다 싶어서 추가 커밋으로 코드를 바꿨습니다.
📝 어떤 부분에 집중해서 리뷰해야 할까요?
📚 참고 자료, 할 말