Skip to content
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

[Spring MVC (인증)] 김진학 미션 제출합니다. #121

Open
wants to merge 14 commits into
base: iampingu99
Choose a base branch
from

Conversation

iampingu99
Copy link

@iampingu99 iampingu99 commented Jan 23, 2025

🏃‍♂️ 과정

이전 단계의 리뷰를 추가로 반영하고 새 단계의 요구사항을 추가했습니다. 역할 분리와 테스트에 대한 관점이 조금씩 만들어지는 것 같습니다. 이번 리뷰도 잘 부탁드립니다.

만료 는 비즈니스 상 충분히 발생할 수 있는 요소라 생각합니다.

이런 맥락에서 자신이 이 내용은 여기서 테스트를 해야겠다. 이 부분은 또 테스트를 할 필요 없겠는데. 를 만들어가면 좋을거 같아요.

  • 테스트명 수정
  • 토큰 서명 단위 테스트 삭제: 라이브러리의 일반적인(응답 비교) 검증은 제외
  • 토큰 만료 단위 테스트 수정: 비즈니스 상 발생할 가능성이 높은 테스트 환경 조성을 위해 토큰 생성 객체에서 토큰 생성 날짜를 외부 객체에서 주입받아 역할을 분리
  • 응답 바디 텍스트 검증 유지: 직관적인 메세지를 확인하기 위해 예상되는 예외가 올바른 메세지를 가지는지 확인

📃 요구사항

로그인 리팩터링

로직

  • HandlerMethodArgumentResolver 를 사용하여 컨트롤러 진입 전 인증 정보 검증

예약 생성 기능 변경

로직

  • name이 없는 경우 Cookie에서 인증 정보 추출 후 예약하는 기능 추가

예외

  • 로그인을 하지 않은 경우
  • 예약 정보가 유효하지 않은 경우

관리자 기능

로직

  • /admin 으로 시작하는 모든 경로는 admin 권한이 있는 사람만 접근할 수 있도록 제한
  • 컨트롤러 이전 단계에서 관리자 권한을 검증하는 HandlerIntercepter 과 로그인 객체를 생성하는 HandlerMethodArgumentResolver 동작 중, 쿠키에서 인증 토큰을 추출하고 객체를 생성하는 동작이 중복되었습니다. 이에 인증 토큰을 추출하는 역할은 AuthorizationExtractor 와 CookieAuthorizationExtractor 로 분리하게 되었고, 인증 객체를 생성하는 역할은 AuthService 에 두게 되었습니다.

🔎 궁금한점

로그인 상태가 필요한 모든 기능들에 대해서 로그인 요청 로직이 중복되었습니다. 이에 따라 아래와 같은 방법을 생각해보았습니다.

  • 로그인과 같이 공통적으로 사용되는 로직을 객체로 분리하여 테스트에서 주입받는 방법: createToken 메서드의 경우 다른 곳에서도 사용될 가능성이 높다고 생각합니다.
  • 이전에 작성한 테스트 객체를 주입받아 성공 메서드를 재사용하는 방법: 로그인 요청이 성공해야 하므로 로그인 성공 테스트 메서드를 사용할 수 있다고 생각합니다.

연쇄적으로 일어나야 하는 테스트에 대해서 이전 단계가 성공했다고 가정하고 단위 테스트로 쪼개거나, 통합 테스트에서 중복을 해결해야할 것으로 생각되는데 생각의 방향이 맞는지 궁금합니다.

만료된 토큰을 테스트하기 위해 토큰 생성 객체에서 날짜 처리를 분리해 발행날짜를 주입받도록 함

BREAKING CHANGE: 토큰 서명 테스트는 제거됨
로그인 확인 또는 어드민 권한 검사에 중복되는 인증 토큰 추출 로직을 외부 객체로 분리
로그인 확인 또는 어드민 권한 검사에 중복되는 인증 객체 생성 로직을 AuthService 로 분리
키 값이 잘못 사용될 수 있는 Map 객체 대신 Claim 객체 사용
Jackson은 isXXX 메서드를 JSON 필드로 간주하여 직렬화/역직렬화 작업에 포함하므로 @JsonIgnore 로 무시하도록
함
Copy link

@youngsu5582 youngsu5582 left a comment

Choose a reason for hiding this comment

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

우선 MVC 중점으로 리뷰 시작하겠습니다~

제가 남긴 의견들은 당연히 반박해주셔도 좋아요~
리뷰 반영하고 다시 멘션 주세요 🙂

import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class AdminInterceptor implements HandlerInterceptor {

Choose a reason for hiding this comment

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

Interceptor 를 사용했네요.
Interceptor 와 Filter 의 차이점이 뭔가요?

public record LoginMember(
String email,
String name,
String role

Choose a reason for hiding this comment

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

클린코드 관점에서 Role 이라는 ENUM 을 만들어도 될 거 같네요.

isAdmin 역시도 Role 에서 메소드로 가지고 있고 LoginMember 는 호출만 해도 되겠네용

reservationRequest.put("theme", "1");

//when
ReservationResponse reservationResponse = sendCreateReservationsRequest(reservationRequest, token).as(

Choose a reason for hiding this comment

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

직접 DTO 를 넘긴게 아니라 MAP 으로 넘겼는데 의도가 있을까요?
( 틀린게 아님. 의견 묻는거임 )

@Test
void 비로그인_상태에서_예약할_경우_예약에_실패한다() {
//given
Map<String, String> reservationRequest = new HashMap<>();

Choose a reason for hiding this comment

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

request 를 만드는 부분도 private 메소드로 더 간편하게 해도 되겠네요.

throws Exception {

String token = authorizationExtractor.extract(request);
LoginMember loginMember = authService.createAuthentication(token);

Choose a reason for hiding this comment

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

LoginMember.from() 부분에서 Claims 에 해당하는 값이 없으면 예외가 터질거 같은데 이 경우 어떻게 되나요?

import org.springframework.web.method.support.ModelAndViewContainer;

@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

Choose a reason for hiding this comment

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

HandlerMethodArgumentResolver 가 정확하게 하는게 뭔가요?

if (reservationRequest.getName() == null
|| reservationRequest.getDate() == null
public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, LoginMember loginMember) {
if (reservationRequest.getDate() == null

Choose a reason for hiding this comment

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

물론, 기존 코드에서 검증을 여기서 하지만
DTO 가 스스로가 메소드로 자신의 값들이 타당한지validXXX 와 같은 메소드를 가지는것도 좋을거 같은데 어떤가요??

Controller 가 DTO 의 특정 요소가 null 인걸 알 필요가 있을까? 라고 생각해서 입니다.

return ResponseEntity.badRequest().body("Invalid reservation request");
}

if (reservationRequest.getName() == null) {

Choose a reason for hiding this comment

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

이 부분도 위와 비슷하게 getName 이 null 인지 + 새로운 객체 생성을 DTO 내부로 은닉해도 될 거 같아요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants