Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import com.example.solidconnection.auth.client.config.AppleOAuthClientProperties;
import com.example.solidconnection.auth.dto.oauth.AppleTokenDto;
import com.example.solidconnection.auth.dto.oauth.AppleUserInfoDto;
import com.example.solidconnection.auth.dto.oauth.OAuthUserInfoDto;
import com.example.solidconnection.auth.service.oauth.OAuthClient;
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.siteuser.domain.AuthType;
import io.jsonwebtoken.Jwts;
import java.security.PublicKey;
import java.util.Objects;
Expand All @@ -27,20 +30,26 @@
* */
@Component
@RequiredArgsConstructor
public class AppleOAuthClient {
public class AppleOAuthClient implements OAuthClient {

private final RestTemplate restTemplate;
private final AppleOAuthClientProperties properties;
private final AppleOAuthClientSecretProvider clientSecretProvider;
private final ApplePublicKeyProvider publicKeyProvider;

public AppleUserInfoDto processOAuth(String code) {
@Override
public AuthType getAuthType() {
return AuthType.APPLE;
}

@Override
public OAuthUserInfoDto getUserInfo(String code) {
String idToken = requestIdToken(code);
PublicKey applePublicKey = publicKeyProvider.getApplePublicKey(idToken);
return new AppleUserInfoDto(parseEmailFromToken(applePublicKey, idToken));
}

public String requestIdToken(String code) {
private String requestIdToken(String code) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> formData = buildFormData(code);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import com.example.solidconnection.auth.client.config.KakaoOAuthClientProperties;
import com.example.solidconnection.auth.dto.oauth.KakaoTokenDto;
import com.example.solidconnection.auth.dto.oauth.KakaoUserInfoDto;
import com.example.solidconnection.auth.dto.oauth.OAuthUserInfoDto;
import com.example.solidconnection.auth.service.oauth.OAuthClient;
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.siteuser.domain.AuthType;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpEntity;
Expand All @@ -27,12 +30,18 @@
* */
@Component
@RequiredArgsConstructor
public class KakaoOAuthClient {
public class KakaoOAuthClient implements OAuthClient {

private final RestTemplate restTemplate;
private final KakaoOAuthClientProperties kakaoOAuthClientProperties;

public KakaoUserInfoDto getUserInfo(String code) {
@Override
public AuthType getAuthType() {
return AuthType.KAKAO;
}

@Override
public OAuthUserInfoDto getUserInfo(String code) {
String kakaoAccessToken = getKakaoAccessToken(code);
return getKakaoUserInfo(kakaoAccessToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
import com.example.solidconnection.auth.service.EmailSignInService;
import com.example.solidconnection.auth.service.EmailSignUpService;
import com.example.solidconnection.auth.service.EmailSignUpTokenProvider;
import com.example.solidconnection.auth.service.oauth.AppleOAuthService;
import com.example.solidconnection.auth.service.oauth.KakaoOAuthService;
import com.example.solidconnection.auth.service.oauth.OAuthService;
import com.example.solidconnection.auth.service.oauth.OAuthSignUpService;
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.common.exception.ErrorCode;
Expand All @@ -40,8 +39,7 @@ public class AuthController {

private final AuthService authService;
private final OAuthSignUpService oAuthSignUpService;
private final AppleOAuthService appleOAuthService;
private final KakaoOAuthService kakaoOAuthService;
private final OAuthService oAuthService;
private final EmailSignInService emailSignInService;
private final EmailSignUpService emailSignUpService;
private final EmailSignUpTokenProvider emailSignUpTokenProvider;
Expand All @@ -53,7 +51,7 @@ public ResponseEntity<OAuthResponse> processAppleOAuth(
@Valid @RequestBody OAuthCodeRequest oAuthCodeRequest,
HttpServletResponse httpServletResponse
) {
OAuthResponse oAuthResponse = appleOAuthService.processOAuth(oAuthCodeRequest);
OAuthResponse oAuthResponse = oAuthService.processOAuth(AuthType.APPLE, oAuthCodeRequest);
if (oAuthResponse instanceof OAuthSignInResponse signInResponse) {
refreshTokenCookieManager.setCookie(httpServletResponse, signInResponse.refreshToken());
}
Expand All @@ -65,7 +63,7 @@ public ResponseEntity<OAuthResponse> processKakaoOAuth(
@Valid @RequestBody OAuthCodeRequest oAuthCodeRequest,
HttpServletResponse httpServletResponse
) {
OAuthResponse oAuthResponse = kakaoOAuthService.processOAuth(oAuthCodeRequest);
OAuthResponse oAuthResponse = oAuthService.processOAuth(AuthType.KAKAO, oAuthCodeRequest);
if (oAuthResponse instanceof OAuthSignInResponse signInResponse) {
refreshTokenCookieManager.setCookie(httpServletResponse, signInResponse.refreshToken());
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.solidconnection.auth.service.oauth;

import com.example.solidconnection.auth.dto.oauth.OAuthUserInfoDto;
import com.example.solidconnection.siteuser.domain.AuthType;

public interface OAuthClient {

OAuthUserInfoDto getUserInfo(String code);

AuthType getAuthType();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.solidconnection.auth.service.oauth;

import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.common.exception.ErrorCode;
import com.example.solidconnection.siteuser.domain.AuthType;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;

@Component
public class OAuthClientMap {

private final Map<AuthType, OAuthClient> oauthClientMap;

public OAuthClientMap(List<OAuthClient> oAuthClientList) {
this.oauthClientMap = oAuthClientList.stream()
.collect(Collectors.toMap(OAuthClient::getAuthType, Function.identity()));
}

public OAuthClient getOAuthClient(AuthType authType) {
OAuthClient oauthClient = oauthClientMap.get(authType);
if (oauthClient == null) {
throw new CustomException(
ErrorCode.NOT_DEFINED_ERROR,
"처리할 수 있는 OAuthClient가 없습니다. authType: " + authType.name()
);
}
return oauthClient;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.solidconnection.auth.service.oauth;


import com.example.solidconnection.auth.dto.SignInResponse;
import com.example.solidconnection.auth.dto.oauth.OAuthCodeRequest;
import com.example.solidconnection.auth.dto.oauth.OAuthResponse;
Expand All @@ -12,50 +11,45 @@
import com.example.solidconnection.siteuser.domain.SiteUser;
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/*
* OAuth 제공자로부터 이메일을 받아 기존 회원인지, 신규 회원인지 판별하고, 이에 따라 다르게 응답한다.
* 기존 회원 : 로그인한다.
* 신규 회원 : 회원가입할 때 필요한 정보를 제공한다.
* */
public abstract class OAuthService {
@Service
@RequiredArgsConstructor
public class OAuthService {

private final OAuthSignUpTokenProvider OAuthSignUpTokenProvider;
private final SignInService signInService;
private final SiteUserRepository siteUserRepository;

protected OAuthService(OAuthSignUpTokenProvider OAuthSignUpTokenProvider, SiteUserRepository siteUserRepository, SignInService signInService) {
this.OAuthSignUpTokenProvider = OAuthSignUpTokenProvider;
this.siteUserRepository = siteUserRepository;
this.signInService = signInService;
}
Comment on lines -28 to -32
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

자식이 부모의 의존성을 주입하는 코드가 없어졌습니다🎉

private final OAuthClientMap oauthClientMap;

@Transactional
public OAuthResponse processOAuth(OAuthCodeRequest oauthCodeRequest) {
OAuthUserInfoDto userInfoDto = getOAuthUserInfo(oauthCodeRequest.code());
String email = userInfoDto.getEmail();
Optional<SiteUser> optionalSiteUser = siteUserRepository.findByEmailAndAuthType(email, getAuthType());
public OAuthResponse processOAuth(AuthType authType, OAuthCodeRequest codeRequest) {
OAuthClient oauthClient = oauthClientMap.getOAuthClient(authType);
OAuthUserInfoDto userInfo = oauthClient.getUserInfo(codeRequest.code());
Optional<SiteUser> optionalSiteUser = siteUserRepository.findByEmailAndAuthType(userInfo.getEmail(), authType);

if (optionalSiteUser.isPresent()) {
SiteUser siteUser = optionalSiteUser.get();
return getSignInResponse(siteUser);
}

return getSignUpPrepareResponse(userInfoDto);
return getSignUpPrepareResponse(userInfo, authType);
}

protected final OAuthSignInResponse getSignInResponse(SiteUser siteUser) {
private OAuthSignInResponse getSignInResponse(SiteUser siteUser) {
SignInResponse signInResponse = signInService.signIn(siteUser);
return new OAuthSignInResponse(true, signInResponse.accessToken(), signInResponse.refreshToken());
}

protected final SignUpPrepareResponse getSignUpPrepareResponse(OAuthUserInfoDto userInfoDto) {
String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(userInfoDto.getEmail(), getAuthType());
private SignUpPrepareResponse getSignUpPrepareResponse(OAuthUserInfoDto userInfoDto, AuthType authType) {
String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(userInfoDto.getEmail(), authType);
return SignUpPrepareResponse.of(userInfoDto, signUpToken);
}

protected abstract OAuthUserInfoDto getOAuthUserInfo(String code);

protected abstract AuthType getAuthType();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.solidconnection.auth.service.oauth;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.common.exception.ErrorCode;
import com.example.solidconnection.siteuser.domain.AuthType;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("OAuthClientMap 테스트")
class OAuthClientMapTest {

@Test
void AuthType에_해당하는_Client를_반환한다() {
// given
OAuthClient appleClient = mock(OAuthClient.class);
OAuthClient kakaoClient = mock(OAuthClient.class);
given(appleClient.getAuthType()).willReturn(AuthType.APPLE);
given(kakaoClient.getAuthType()).willReturn(AuthType.KAKAO);

OAuthClientMap oAuthClientMap = new OAuthClientMap(
List.of(appleClient, kakaoClient)
);

// when & then
assertAll(
() -> assertThat(oAuthClientMap.getOAuthClient(AuthType.APPLE)).isEqualTo(appleClient),
() -> assertThat(oAuthClientMap.getOAuthClient(AuthType.KAKAO)).isEqualTo(kakaoClient)
);
}

@Test
void AuthType에_매칭되는_Client가_없으면_예외가_발생한다() {
// given
OAuthClient appleClient = mock(OAuthClient.class);
given(appleClient.getAuthType()).willReturn(AuthType.APPLE);

OAuthClientMap oAuthClientMap = new OAuthClientMap(
List.of(appleClient)
);

// when & then
assertThatCode(() -> oAuthClientMap.getOAuthClient(AuthType.KAKAO))
.isInstanceOf(CustomException.class)
.hasMessageContaining(ErrorCode.NOT_DEFINED_ERROR.getMessage());
}
}
Loading
Loading