[그리디] 김민욱 SpringCore 7~9단계 제출합니다. - #274
Conversation
70825
left a comment
There was a problem hiding this comment.
안녕하세요 민욱님~ 다시 뵙네요 잘부탁드려요~!! 🙇♂️
PR 본문에 내용 잘 적어주셔서 민욱님이 어떤 방향으로 생각하고 공부하셨는지 잘 이해가 됐어요. 관련해서 저도 본문에 추가로 내용 적어둘게요
추가적으로 민욱님 리뷰 보면서 느낀건데 미션 진행하면서 궁금한 부분도 추가로 적어주시면 좋을 것 같아요!! 이미 궁금한걸 다 찾아보고 해결하신거라면 어쩔 수 없지만 😄 호옥시 있으면 적어주시길 바래요
코드 리뷰의 경우에는 이전 미션 마지막 커밋을 참고해서 여기 범위만 봤었는데 혹시 아니라면 코멘트 부탁드려요~
따라서, 사용자 정보 변경을 재발급된 Access Token에 반영하기 위해, Refresh Token으로 Access Token을 재발급할 때 DB에서 회원을 다시 조회하도록 리팩터링했습니다.
오호 빈틈 없는 설계 좋습니다 👍
그런데 궁금한 부분이 있는데 /token/refresh를 통해 재발급을 하는 것 같은데, 현재 서버 실행하면 사용되는 곳은 없는거죠?? 만약 정보 변경 기능이 생긴다면 해당 API를 요청하는거로 이해했는데 맞을까요?
다만 Refresh Token으로 새로운 Access Token을 발급할 때는 변경된 회원 정보를 반영하기 위해 의도적으로 DB를 조회하도록 했습니다.
요거는 저도 민욱님이 생각한대로 잘 이해하고 만드신 것 같아요~
CommandLineRunner
👍👍
|
|
||
| public class JwtUtils { |
| return new LoginMemberInfo( | ||
| claims.get("id", Number.class).longValue(), | ||
| claims.get("name", String.class), | ||
| claims.getSubject(), | ||
| MemberRole.from(claims.get("role", String.class)) | ||
| ); |
There was a problem hiding this comment.
이거는 LoginMemberInfo에 정적 팩토리 메서드를 만들어서 관리하는건 어떻게 생각하시나요?
정팩메로 안에 넣어주면 조금이나마 더 깔끔한 코드가 나올 것 같아서요!
| @Component | ||
| @Profile("test") | ||
| public class TestDataLoader implements CommandLineRunner { |
There was a problem hiding this comment.
테스트에서 사용하는 클래스는 테스트 패키지쪽에 넣어두는게 더 목적에 맞게 배치해두는 것 같다고 생각하는데 어떻게 생각하시나요??
| spring.datasource.url=jdbc:h2:mem:database;DB_CLOSE_ON_EXIT=FALSE | ||
| spring.jpa.hibernate.ddl-auto=create-drop |
There was a problem hiding this comment.
DB_CLOSE_ON_EXIT=FALSE- spring.jpa.hibernate.ddl-auto=
create-drop
위 옵션은 각각 어떤 역할을 하게 되는 것일까요?
| @Component | ||
| @Profile("!test") | ||
| public class DataLoader implements CommandLineRunner { | ||
| private final MemberDao memberDao; |
There was a problem hiding this comment.
요기는 Dao로 네이밍을 정하게된 이유가 있나요??
다른 분들 보면 Repository로 네이밍을 정해두는데 민욱님은 Dao로 해두셔서 이유가 궁금해요
|
|
||
| @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) | ||
| @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) | ||
| @ActiveProfiles("test") |
There was a problem hiding this comment.
여기는 테스트 코드 파일이 여러개 생긴다면 매번 클래스 위에 @ActiveProfiles("test")를 붙여야해서 불편할 수도 있는데요
test에도 application.properties 파일을 추가한다면 @ActiveProfiles("test")를 붙이지 않아도 될 것 같은데 한 번 수정해보시겠어요?
소개
안녕하세요 다빈 리뷰어님 ~
세종대 그리디 4기 백엔드 김민욱입니다!
깊은 내용이 꼭 아니더라도 키워드나 방향성만 제시해 주신다면, 스스로 공부를 이어나갈 수 있습니다 !
PR 본문은 다음과 같이 구성되어 있습니다.
리뷰어님께서 시간이 없으시다면, 셀프 리뷰를 바탕으로 부족한 부분등에 대해서 자유롭게 리뷰를 남겨주시면 감사하겠습니다!
단계별 구현 사항
7단계
roomescape와 같은 계층의jwt패키지로 분리8단계
schema.sql대신 데이터베이스를 초기화하는 클래스 생성셀프 리뷰
사용자 정보 변경을 새로 발급하는 Access Token에 반영할 수 있는가?
기존 방식은 Refresh Token 안에 저장된 사용자 ID와 권한을 그대로 이용해 새로운 Access Token을 만들었습니다.
예를 들어, Refresh Token에 다음 정보가 저장되어 있습니다.
{ "id": 1, "role": "ADMIN" }DB에서 해당 사용자의 권한을
ADMIN에서USER로 변경해도 기존 Refresh Token에는 계속ADMIN권한이 들어 있습니다. 따라서 Refresh Token의 정보만 사용해 Access Token을 재발급하면 새로운 Access Token에도ADMIN권한이 들어갈 수 있습니다.이것이 기존 코드의 문제점이라고 생각하였습니다.
따라서, 사용자 정보 변경을 재발급된 Access Token에 반영하기 위해, Refresh Token으로 Access Token을 재발급할 때 DB에서 회원을 다시 조회하도록 리팩터링했습니다.
이렇게 하면 회원의 이름, 이메일, 권한이 변경되거나 회원이 삭제됐을 때 DB의 최신 상태를 확인할 수 있습니다.
이미 발급된 Access Token의 정보가 즉시 변경되는 것은 아니지만, Refresh Token을 이용해 Access Token을 재발급하는 시점에는 DB에서 조회한 최신 사용자 정보를 반영할 수 있도록 설계했습니다.
학습 내용 정리
@Configuration과 빈 등록은 DB 접근 최소화와 어떤 관계가 있는가?문제의 요구 사항에서
이 두가지와 @configuration 가 무슨 상관인지 이해가 되지 않았었습니다.
하지만 결과적으로
불필요한 DB 조회를 최소화 할 수 있는 이유는
@Configuration이나@Bean를 활용하여,JWT 파싱 책임을
JwtUtils로 분리하고,AuthUserArgumentResolver가 회원을 다시 조회하지 않고 Access Token의 정보를 사용하도록 의존 관계를 변경할 수 있기 때문에 DB 접근을 최소화 할 수 있음을 학습하였습니다.기존 코드는
JwtUtils가@Component로 등록되어 있어서 특정 비즈니스 로직과 강하게 결합되어 있는 형태였습니다.JWT 토큰 하나를 확인하기 위해 불필요한 DB 조회까지 실행될 수 있다고 합니다.
JwtUtils는 JWT 생성과 파싱만 담당하는 것으로 스스로 정의했기 때문에 Spring이나 회원 저장소에 직접 의존할 필요가 없습니다. 이에 따라JwtUtils를roomescape패키지 외부의jwt패키지로 분리했습니다.외부로 분리한 뒤에는
@Configuration과@Bean을 사용해JwtUtils를 명시적으로 빈으로 등록했습니다.이렇게 하면
JwtUtils는 JWT 생성과 파싱에만 집중하고, Spring의 컴포넌트 스캔이나 회원 관련 비즈니스 로직과 직접 결합되지 않습니다.AuthUserArgumentResolver가 Access Token을 읽을 때MemberService나MemberDao를 호출하지 않고, 토큰에 포함된 회원 ID와 권한 정보를 바로 사용하도록 의존 관계를 변경했기 때문에 불필요한 DB 조회가 사라졌습니다.다만 Refresh Token으로 새로운 Access Token을 발급할 때는 변경된 회원 정보를 반영하기 위해 의도적으로 DB를 조회하도록 했습니다.
DB 초기화와
CommandLineRunner의 관계기존 프로젝트에서는
schema.sql을 사용했습니다.현재 프로젝트는 하나의
schema.sql에서 초기 데이터를 모두 관리하고 있었기 때문에 실행 환경별 데이터를 구분하기 어려웠습니다. 테이블이나 엔티티 구조가 변경되면 SQL도 직접 수정해야 했습니다.이를 개선하기 위해
CommandLineRunner를 구현한 Loader에서 Repository를 통해 초기 데이터를 저장하도록 변경했습니다.초기 데이터는 프로파일에 따라 구분했습니다.
DataLoader:test프로파일을 제외한 일반 실행 환경의 회원 데이터 등록TestDataLoader: 테스트에 필요한 회원, 테마, 시간, 예약 데이터 등록@Profile을 사용해 실행 환경에 맞는 Loader만 등록테이블 생성은 Loader가 아니라 Hibernate가 담당합니다.
Hibernate가 JPA 엔티티를 기준으로 테이블을 생성하고, Loader는 생성된 테이블에 초기 데이터를 저장합니다.
내부적으로는 다음과 비슷한 SQL이 실행된다고 합니다.
마무리
소중한 시간을 내어 리뷰해 주시는 만큼, 남겨주신 내용을 바탕으로 이번 주 학습 내용을 더 깊이 정리해 보겠습니다.