Skip to content

Commit

Permalink
[#37] feat: 애플 로그인 시 회원 이름, 이메일 저장
Browse files Browse the repository at this point in the history
  • Loading branch information
kimyu0218 committed Feb 4, 2025
1 parent a98eed6 commit 43ba5e7
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ public class OauthService {
public Long kakaoLogin(final KakaoLoginCommand command) {
final KakaoTokenResponse token =
getKakaoToken(command.authorizationCode(), command.redirectUri());
log.info("kakao 토큰 받아오기 완료");
final KakaoUserInfoResponse userInfo = getKakaoUserInfo(token.accessToken());
log.info("kakao 사용자 정보 받아오기 완료");

final String oauthId = userInfo.id().toString();
final Member member = findKakaoMember(oauthId);
final Member member = findMemberWithSocialProvider(oauthId, SocialProvider.KAKAO);
if (member == null) {
final Member newMember =
memberRepository.save(
Expand All @@ -64,14 +62,6 @@ public Long kakaoLogin(final KakaoLoginCommand command) {
return member.getId();
}

private Member findKakaoMember(final String oauthId) {
return socialAccountRepository
.findByOauthIdAndSocialProviderAndDeletedAtIsNull(oauthId, SocialProvider.KAKAO)
.map(SocialAccount::getMember)
.filter(member -> member.getDeletedAt() == null)
.orElse(null);
}

private KakaoUserInfoResponse getKakaoUserInfo(final String accessToken) {
return kakaoClient.requestUserInfo(BEARER_PREFIX + accessToken);
}
Expand All @@ -87,24 +77,31 @@ private KakaoTokenResponse getKakaoToken(
return kakaoAuthClient.requestToken(params);
}

private Member findMemberWithSocialProvider(
final String oauthId, final SocialProvider socialProvider) {
return socialAccountRepository
.findByOauthIdAndSocialProviderAndDeletedAtIsNull(oauthId, socialProvider)
.map(SocialAccount::getMember)
.filter(member -> member.getDeletedAt() == null)
.orElse(null);
}

@Transactional
public Long appleLogin(final AppleLoginCommand command) {
AppleIdToken appleIdToken = AppleIdToken.of(command.idToken());
final String jwtClaims = appleIdToken.decodePayload();
final AppleAuthorization authorization = decodeAppleIdTokenPayload(jwtClaims);

return socialAccountRepository
.findByOauthIdAndSocialProviderAndDeletedAtIsNull(
authorization.getSub(), SocialProvider.APPLE)
.map(account -> account.getMember().getId())
.orElseGet(
() -> {
final Member member =
memberRepository.save(Member.create("TODO: name", "TODO: email"));
socialAccountRepository.save(
SocialAccount.appleSignUp(authorization.getSub(), member));
return member.getId();
});
final Member member =
findMemberWithSocialProvider(authorization.getSub(), SocialProvider.APPLE);
if (member == null) {
final Member newMember =
memberRepository.save(Member.create(command.name(), authorization.getEmail()));
socialAccountRepository.save(SocialAccount.appleSignUp(authorization.getSub(), newMember));
return newMember.getId();
}
member.updateUserInfo(command.name(), authorization.getEmail());
return member.getId();
}

private AppleAuthorization decodeAppleIdTokenPayload(final String appleJwtClaims) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@

import static org.assertj.core.api.Assertions.tuple;
import static org.assertj.core.api.BDDAssertions.then;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.nexters.jaknaesocore.common.support.IntegrationTest;
import org.nexters.jaknaesocore.domain.auth.restclient.dto.KakaoTokenResponse;
import org.nexters.jaknaesocore.domain.auth.restclient.dto.KakaoUserInfoResponse;
import org.nexters.jaknaesocore.domain.auth.restclient.dto.KakaoUserInfoResponse.KakaoAccount;
import org.nexters.jaknaesocore.domain.auth.service.dto.AppleLoginCommand;
import org.nexters.jaknaesocore.domain.auth.service.dto.KakaoLoginCommand;
import org.nexters.jaknaesocore.domain.member.model.Member;
import org.nexters.jaknaesocore.domain.member.repository.MemberRepository;
import org.nexters.jaknaesocore.domain.socialaccount.model.SocialAccount;
Expand All @@ -30,6 +38,23 @@ void tearDown() {
memberRepository.deleteAllInBatch();
}

private SocialAccount createSocialAccount(
final Member member, final String oauthId, final SocialProvider socialProvider) {
return SocialAccountFixture.builder()
.member(member)
.oauthId(oauthId)
.socialProvider(socialProvider)
.build();
}

private AppleLoginCommand createAppleLoginCommand(String idToken, String name) {
return new AppleLoginCommand(idToken, name);
}

private KakaoLoginCommand createKakaoLoginCommand(String authorizationCode, String redirectUri) {
return new KakaoLoginCommand(authorizationCode, redirectUri);
}

@Nested
@DisplayName("appleLogin 메소드는 ")
class appleLogin {
Expand All @@ -45,7 +70,10 @@ void shouldSignIn() {
"eyJraWQiOiJBSURPRkZDTzJDM05EUVBGQUJDVEFDT1VDU1ZZQUdTR09ZUEJNVU5KS1FEUVFBQUEyTVE2USIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIwMDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIiLCJhdF9oYXNoIjoiUlZfdkZKZnFhdDBGMmFZdHVQUlNlZyIsImF1ZCI6ImNvbS5leGFtcGxlLmFwcGxpbmUud2ViIiwiYXV0aF90aW1lIjoxNjA1MzcxNTU5LCJpc3MiOiJodHRwczovL2lkLmFwcGxlLmNvbSIsImV4cCI6MTYwNTM3NTE1OSwiaWF0IjoxNjA1MzcxNTU5LCJub25jZSI6Ijc5NDc5NTg4MzA1NDQ2OTQzNiIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlfQ.VkmD8KcTtCmN65DPwhAPoOeRuXmsLqnm1z8pWa_qHG3xD2LBJgj9YOZPUKseOlfrOz5e5JgIR1qPdWiL2QFuyjCQZ0PSG0hV1xtQ_yYbVHeqLaID0AgcV8Hxldg9hFvF_jvM8G_mo0S9-D8gOR4kbQ";
sut.appleLogin(createAppleLoginCommand(idToken, "홍길동"));

then(memberRepository.findAll()).hasSize(1);
then(memberRepository.findAll())
.hasSize(1)
.extracting("name", "email")
.containsExactly(tuple("홍길동", "[email protected]"));
then(socialAccountRepository.findAll())
.hasSize(1)
.extracting("oauthId", "socialProvider")
Expand All @@ -60,7 +88,7 @@ class whenMemberFound {
@Test
@DisplayName("토큰을 발행한다.")
void shouldIssueToken() {
final Member member = memberRepository.save(Member.create());
final Member member = memberRepository.save(Member.create("홍길동", "[email protected]"));
final String oauthId = "001234567890123456789012";
socialAccountRepository.save(createSocialAccount(member, oauthId, SocialProvider.APPLE));

Expand All @@ -74,16 +102,58 @@ void shouldIssueToken() {
}
}

private SocialAccount createSocialAccount(
final Member member, final String oauthId, final SocialProvider socialProvider) {
return SocialAccountFixture.builder()
.member(member)
.oauthId(oauthId)
.socialProvider(socialProvider)
.build();
}
@Nested
@DisplayName("kakaoLogin 메소드는")
class kakaoLogin {

@BeforeEach
void setUp() {
given(kakaoAuthClient.requestToken(any()))
.willReturn(new KakaoTokenResponse("bearer", "access token", 1, "refresh token", 1));
given(kakaoClient.requestUserInfo("Bearer access token"))
.willReturn(new KakaoUserInfoResponse(1L, new KakaoAccount("홍길동", "[email protected]")));
}

private AppleLoginCommand createAppleLoginCommand(String idToken, String name) {
return new AppleLoginCommand(idToken, name);
@Nested
@DisplayName("id값과 일치하는 유저를 찾지 못하면")
class whenMemberNotFound {

@Test
@DisplayName("회원가입을 진행한다.")
void shouldSignIn() {
sut.kakaoLogin(createKakaoLoginCommand("카카오 인가 코드", "카카오 로그인 리다이렉트 URI"));

assertAll(
() ->
then(memberRepository.findAll())
.hasSize(1)
.extracting("name", "email")
.containsExactly(tuple("홍길동", "[email protected]")),
() ->
then(socialAccountRepository.findAll())
.hasSize(1)
.extracting("oauthId", "socialProvider")
.containsExactlyInAnyOrder(tuple("1", SocialProvider.KAKAO)));
}
}

@Nested
@DisplayName("id값과 일치하는 유저를 찾으면")
class whenMemberFound {

@Test
@DisplayName("로그인을 진행한다.")
void shouldSignIn() {
final Member member = memberRepository.save(Member.create("홍길동", "[email protected]"));
final String oauthId = "1";
socialAccountRepository.save(createSocialAccount(member, oauthId, SocialProvider.KAKAO));

sut.kakaoLogin(createKakaoLoginCommand("카카오 인가 코드", "카카오 로그인 리다이렉트 URI"));

assertAll(
() -> then(memberRepository.findAll()).hasSize(1),
() -> then(socialAccountRepository.findAll()).hasSize(1));
}
}
}
}

This file was deleted.

0 comments on commit 43ba5e7

Please sign in to comment.