-
Notifications
You must be signed in to change notification settings - Fork 8
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
Authorization header를 사용하는 인증 클래스 생성 #954
Conversation
Co-authored-by: jminkkk <[email protected]>
Co-authored-by: jminkkk <[email protected]>
Co-authored-by: jminkkk <[email protected]>
Co-authored-by: jminkkk <[email protected]>
Co-authored-by: zangsu <[email protected]>
Co-authored-by: zangsu <[email protected]>
Co-authored-by: zangsu <[email protected]>
Co-authored-by: zangsu <[email protected]>
Co-authored-by: jminkkk <[email protected]>
Co-authored-by: jminkkk <[email protected]>
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.
테스트가 아주 꼼꼼하네요~~
면접으로 바쁜 와중에 고생했어요!!
나름대로 꼼꼼히 보려고 노력했습니다 🔥
backend/src/main/java/codezap/auth/configuration/AuthWebConfiguration.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/codezap/auth/controller/AuthController.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/codezap/auth/manager/CookieCredentialManager.java
Outdated
Show resolved
Hide resolved
|
||
boolean hasCredential(HttpServletRequest httpServletRequest); | ||
|
||
void setCredential(HttpServletResponse httpServletResponse, String credential); | ||
void setCredential(HttpServletResponse httpServletResponse, Member member); |
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.
HttpServletResponse와 Member가 맞닿아있어서 불안하네요.
우리가 지금까지 DTO를 사용해 도메인과 웹을 격리했는데, 이렇게 되면 일관성이 깨지는 것 같아요.
CredentialManager와 CredentialProvider는 우리의 계층 구조에서 어디에 위치한다고 생각하나요?
저는 presentation 또는 web이라고 일컫는 계층에 있다고 생각하는데, 얘기를 나눠보고 싶네요.
자바 기본 타입을 사용하거나, DTO를 만들어서 데이터를 주고 받는 게 어떨까요?
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.
CredentialManager
는 단순히 인증 정보를 응답에 설정해 주는 책임만 가지도록 개선하였습니다.
이 과정에서 다시 CredentialManager
와 CredentialProvider
사이의 의존성이 제거되었으며 두 객체 모두 도메인 객체인 Member
와 의존성을 가지지 않도록 LoginMember
라는 dto를 추가하였습니다.
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.
이미 논의가 끝난 후인 것 같은데 다시 이야기해서 미안해요.
저는 반대로 생각해요 🥲
저는 여기서 DTO를 사용하면 일관성이 깨지는 것 같아요. 이 부분이 DTO로 변경되면 우리 이전 논의를 통해 결정했던 AuthArgumentResolver에서 반환하는 것도 Member가 되면 안된다고 생각해요.
제우스 의견처럼 다른 부분에서는 view에 영향을 최소화하기 위해 DTO를 사용하였지만 이 부분의 역할은 view에서 사용하기 위함은 아니라고 생각해요. Http 등 특정 웹 계층 관련 로직이 Member에 영향을 주면 안되지만 여기서는 그 �목적이 반대를 위함이기도 하구요.
오히려 DTO 관리 리소스가 드는 것 같은데 흠 다른 분들은 어떻게 생각하시나요?
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.
너무 어려운 주제군요 ㅠㅠ 고민을 더 해보느라 시간이 걸렸습니다...
결국 도메인과 web 계층을 얼마나 완벽하게 격리시키느냐의 문제인데요.
제가 느끼기에는 Member
도메인을 웹 계층과 완벽하게 분리하는 것은 이상적이지만 그만큼 또 어렵다고 느껴집니다. 몰리 말처럼 지금도 controller의 파라미터로 Member
를 받고 있기도 하고요.
또한, 지금의 로그인이 두 가지 역할을 가지는 것도 어려움을 야기하는 또 다른 문제점인데요.
- 인증 정보를 응답에 포함한다. (Cookie / Authorization 헤더 설정)
- 로그인 정보를 바디에 포함한다. (
LoginResponse
를 반환)
이 때문에 authService.login()
메서드가 Member
, 또는 해당 정보를 갖는 dto를 반환해야 하는 상황이에요.
이 문제에 대한 개인적인 선호는 도메인이 controller 영역까지 노출되거나 HttpServletResponse가 Service 영역까지 침투하는 것도 허용 가능한 범위에요.
특히 지금같은 경우 로그인이라는 기능이 "인증 정보 유지를 위한 설정"의 책임까지 가지고 있기 때문에 authService.login()
메서드의 파라미터로 response를 넘겨주는 것이 가장 마음이 편하기도 하고요.
다만, 이 부분에 대해선 각자 느끼는 기준, 허용치 등이 다를 것 같아서 의견을 더 주시면 감사하겠습니다.
backend/src/test/java/codezap/auth/manager/AuthorizationCredentialManagerTest.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/codezap/auth/manager/AuthorizationCredentialManagerTest.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/codezap/auth/manager/CookieCredentialManagerTest.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/codezap/auth/provider/PlainCredentialProvider.java
Outdated
Show resolved
Hide resolved
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.
짱수 고생했어요! 전반적으로 깔끔한 것 같네요 ! 리뷰를 뭘 할까 열심히 보는데 제우스가 이미 남긴 리뷰 외에 남길 리뷰가 없네요 ..!
제우스 리뷰 중에 동의하는 부분이 많아서 일단 코멘트로 리뷰 남길게요~ 리뷰 반영되고 바로 어프루브 하겠습니다~
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.
대부분 페어로 진행해서 따로 코멘트 남길 부분은 없네요!!
수고했어요 짱수 👍👍👍
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.
으악 리뷰 마감기한이 어제까지였네요...
늦어서 죄송합니다ㅠㅠ
간단하게 확인해봤는데 켬미 말대로 제우스 코멘트 이외에 리뷰할만한 부분이 크게 없는 것 같네요.
너무 고생하셨습니다👍
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.
고생많았어요 짱수~!
NPE 위험이 있어 코멘트 하나만 더 추가했어요 😭
@@ -37,7 +36,7 @@ public Member resolveArgument( | |||
if (!parameterAnnotation.required() && !credentialManager.hasCredential(request)) { |
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.
아래와 같이 테스트코드 추가해서 확인해보니 parameterAnnotation에서 NPE가 발생할 수 있네요.
@Nested
@DisplayName("파라미터 반환 테스트")
class ResolveArgument {
static class ResolveTestController {
public void notRequiredMethod(@AuthenticationPrinciple(required = false) Member member) ...
public void requiredMethod(@AuthenticationPrinciple Member member) ...
public void unsupportedMethod(Member member) {}
}
@Nested
@DisplayName("required 값이 false 일 경우")
class RequiredFalseTest {
Method notRequiredMethod = ...
Method unsupportedMethod = ReflectionSupport.findMethod(
ResolveTestController.class,
"unsupportedMethod",
Member.class).orElseThrow();
@Test
@DisplayName("NPE")
void npeTest() {
assertThatNullPointerException().isThrownBy(() -> resolveArgument(unsupportedMethod, nativeWebRequest));
}
...
그래서 아래와 같이 개선 제안해요~~
if (!parameterAnnotation.required() && !credentialManager.hasCredential(request)) { | |
@Override | |
public Member resolveArgument( | |
@NonNull MethodParameter parameter, | |
ModelAndViewContainer mavContainer, | |
NativeWebRequest webRequest, | |
WebDataBinderFactory binderFactory | |
) { | |
AuthenticationPrinciple parameterAnnotation = parameter.getParameterAnnotation(AuthenticationPrinciple.class); | |
boolean supported = Objects.nonNull(parameterAnnotation); | |
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); | |
if (supported && !parameterAnnotation.required() && !credentialManager.hasCredential(request)) { | |
return null; | |
} | |
Credential credential = credentialManager.getCredential(request); | |
return credentialProvider.extractMember(credential); | |
} |
@@ -1,12 +1,12 @@ | |||
package codezap.auth.dto.response; | |||
|
|||
import codezap.member.domain.Member; | |||
import codezap.auth.dto.LoginMember; | |||
|
|||
public record LoginResponse( | |||
Long memberId, |
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.
혹시 null이 들어올 수 있는 경우가 있나요?
없다면 primitive type long으로 바꾸는게 좋을 것 같아요!
credentialManager.setCredential(httpServletResponse, credential); | ||
return ResponseEntity.ok(LoginResponse.from(loginMember)); |
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.
제우스 리뷰에 코멘트 남긴 것에 이어서 의견 남길게요.
여기서도 LoginMember DTO를 다시 한번 감싼 것이 비용이라고 생각이 돼요 🥲
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.
확인했습니다👍
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.
수고하셨습니다~!!
⚡️ 관련 이슈
#908
📍주요 변경 사항
AuthorizationHeaderCredentialManager
생성CredentialManager
를 생성하였습니다.Credential
클래스 생성Credential
을 생성하였습니다.🎸기타
기존의 코드에서는
CredentialProvider
와CredentialManager
가 개별적으로 동작하고 있었습니다.ex) service에서
CredentialProvider
가String credential
을 생성하고, controller에서CredentialManager
가 응답에 credential 설정다만,
CredentialManager
와CredentialProvider
는 어느 정도 함께 동작해야 하는 문제가 있었습니다. issue comment이에
CredentialProvider
의 외부 사용을 제거하고CredentialManager
에서CredentialProvider
의 의존성을 가지도록 변경하였습니다.🍗 PR 첫 리뷰 마감 기한
12/11 00:00