-
Notifications
You must be signed in to change notification settings - Fork 0
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
[FEAT/#16] 회원가입 API 구현 #30
base: dev
Are you sure you want to change the base?
Conversation
전화번호 인증 이후 진행되는 회원가입 API를 정의합니다. - Body로 `name`과 `phone`, `code` (access code)와 `authPlatform`(GOOGLE/APPLE) 요청
- 회원가입 성공에 대한 Success Code 정의 - Auth - SignUpUsecase 정의 - SignUpCommand 타입 파라미터 선언 - 정의한 API 구현
|
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.
고생하셨습니다 !
역시 깔끔함 탑3
|
||
@Override | ||
@PostMapping("/signup") | ||
public ResponseEntity<BaseResponse<?>> signUp(AuthRequest.SignUp signUp) { |
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.
P3
오 이 부분 signUp이 직관적이긴 한데, 행위를 뜻하는 것 같아서 signUpRequest 정도로 바꾸는건 어떠신가요 ?!
- Map to Headers 생성 팩토리 메서드 - URL & Headers & Body to Request 생성 팩토리 메서드 - Body가 필요한 Post Request 와 Body가 불필요한 Get Request 생성을 분리햇습니다.
클라이언트 <-> 인증 사이에서의 관심사가 혼재되어 정의되어 있던 요소를 수정했습니다.
- Issuer 값 - Public Key Set URL 추가
자세한 내용은 PR 본문을 참고해주세요.
- 외부 통신의 Response 타입이 도메인 레이어까지 범람하는 것을 방지하고자 "XXXResponse" 타입의 return type 에서 String으로 변경했습니다. - 메서드 당 단일 책임 수행 및 반환을 실현하기 위해 Port Class Return Type이 아닌 기본형 타입을 채택했습니다. - 추후 필드 추가 필요 시, Record 타입 변경 및 필드 추가를 고려하는 것이 좋다고 생각했습니다.
인증 단계에서 ID를 알 수 없는 상황이기에 phone 값 기준으로 조회 및 삭제하도록 구현했습니다.
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.
자잘한 리뷰 남겨보았습니다! 볼륨이 큰데 고생하셨습니다 구조 변경 이후가 더 확실히 이해하기 좋은 것 같네요 많이 배워갑니다~
+) 머지 이후에 소셜 로그인도 id token 방식을 사용하도록 코드 변경 이후 사용되지 않는 코드는 삭제하겠습니다!
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class GoogleAuthService implements OAuthService { | ||
private final GoogleOAuthProperty googleOAuthProperty; | ||
private final GoogleAuthClient googleAuthClient; | ||
private final Gson gson; |
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.
p3
더 이상 사용되지 않는 필드인 것 같은데 지우면 좋을 것 같습니다!
SignedJWT signedJWT = SignedJWT.parse(token); | ||
JWK targetJwk = findMatchJWK(signedJWT); | ||
|
||
verifyAppleIdTokenJwt(signedJWT, targetJwk); |
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.
p2
GoogleAuthService인데 이름이 잘못 지어진 것 같아요..!
|
||
if (isBodyNull) { | ||
throw new ClientResponseException(GOOGLE_RESPONSE_UNAVAILABLE); | ||
private void verifyAppleIdTokenJwt(final SignedJWT jwt, JWK jwk) throws ParseException { |
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.
p2
verifyGoogleIdTokenJwt로 변경되면 좋을 것 같습니다!
import static sopt.makers.authentication.support.code.external.failure.ClientError.INVALID_ID_TOKEN; | ||
|
||
import sopt.makers.authentication.domain.auth.AuthPlatform; | ||
import sopt.makers.authentication.external.oauth.dto.IdTokenResponse; | ||
import sopt.makers.authentication.support.exception.external.*; |
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.
p4
와일드카드 제거해주시면 좋을 것 같아요!
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.
고생하셨습니다! 헛발질 했네요 오전에..
저는 성은이가 언급한 내용 말고 추가 논의할 사항은 없는 것 같습니다 !
Related Issue 🚀
Work Description ✏️
회원가입 기능을 구현했습니다.
⚙️ 구현 회원 가입 프로세스
각 플랫폼마다의 회원 가입을 분리하여 구현했습니다.
(아래 플랫폼은
authPlatform
기준으로 분기 처리됩니다)Google
name
,phone
,code
,authPlatform
code
(ID Token) →https://oauth2.googleapis.com/tokeninfo?id_token=ID_TOKEN
호출 (참고 Docs)sub
추출name
&phone
→ UserRegisterInfo 저장소에서 사전 제출 인적정보 조회sub
값 기반 신규 회원(User
) 데이터 생성 및 저장Apple
name
,phone
,code
,authPlatform
code
(ID Token) → ID Token Parsingsub
추출name
&phone
→ UserRegisterInfo 저장소에서 사전 제출 인적정보 조회sub
값 기반 신규 회원(User
) 데이터 생성 및 저장(참고 Apple Docs : Authenticating users with Sign in with Apple, Verifying a user, Generate and validate tokens, JWKS-Keys)
위 API의 Request Body로 전달받는
code
값은ID_TOKEN
(ACCESS_TOKEN
❌) 입니다.🔑 Id Token 검증 방식
PR Point 📸
✅ 인증 과정에서 사용되는 객체들의 책임과 역할
과거 첫 구현 당시 워낙 큰 볼륨의 작업이었기에 빠르게 반영하기 어려울 듯 하여 구체적으로 개선안에 대해 제안드리지 못했었는데요!
이번 기능 구현을 진행하면서 혼재되어 있는 역할과 처리로 인해 작업에 어려움이 있었습니다.
위 구조라면 각 OAuth 플랫폼에서 요구하는 검증/인증 작업에 대한 구현은
xxxAuthService
객체 내에 계속해서 구현해야 하는 상황이었습니다.조금더 유연하고 확장 및 재사용이 가능하도록 개선할 수 있는 요소가 충분히 더 존재하는 것 같습니다.
(ex. Request / Response / Header 생성 Util 객체 분리 등)
추후에 더 논의해보았으면 좋겠습니다.
✅ 인증 프로세스 통일화 (웹 ↔ 네이티브앱)
초반
access_token
과id_token
의 개념이 혼동되어 섣불리 확정 짓기 어려웠는데요.웹 환경과 네이티브 앱 환경에서 모두 동일한 로그인/회원가입 경험을 제공해야했기 때문에 아래와 같은 고민을 했습니다.
이 때, 추후 "유지보수성"와 "빠른 대응성"을 위해 2번 방식이 적합하다고 생각했습니다.
(웹 클라이언트 전달 : Configuring your webpage for Sign in with Apple
✅ Access Token↔️ Id Token
위 언급했듯 2번 방식을 채택함에 따라 각 OAuht 플랫폼의 Token API 공식 문서를 살펴본 결과, 모두 동일하게
access_token
과id_token
을 사용하는 토큰 정책이 적용되어 있고기본적으로 회원가입 절차에서 사용할 사용자 식별값은 각 플랫폼의 토큰들에 내제되어 있는 Unique Identifier
sub
를 사용하고자했습니다.하지만 해당
sub
값은access_token
과id_token
모두에 포함되어 있습니다.하지만 각 공식 문서에서 동일하게 얘기하는 내용은 아래와 같았고 이에 따라 ID Token 사용을 채택했습니다.
✅ 왜 OAuth 플랫폼 계정의 email은 식별값으로 사용하지 않는가
해당 내용은 Google보다는 Apple의 영향이 큽니다.
Apple의 공식 문서에 따르면 아래와 같이 전했습니다.
위와 같이 학교 계정/직장 계정에 대해 불확실성을 가지고 있었기에 필수 식별값으로 사용하기엔 부적합하다고 판단했습니다.
(물론 Apple에서도 private proxy email을 email로 변환하는 방식도 제공하지만 이를 위한 클라이언트와 서버의 추가적인 구현은 비효율적일 것이라고 판단했습니다.)
🤯 도메인 객체의 ID 부재 해결방법...
레퍼런스를 찾아보니 비슷한 고민을 겪은 케이스가 많은 것 같아요.
이에 몇 가지 대안을 찾아왔습니다.
추가적인 내용에 대해서는 BE 정기회의 때 얘기나눠보도록 해요!