Skip to content
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

[refac] oauth 탈퇴 provider 로직 수정, 애플 로그인 변수 적용 및 로직 변경 #69

Merged
merged 13 commits into from
Jul 27, 2023
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ out/
.env.*


Domain/src/main/generated/**/*.java
Domain/src/main/generated/**/*.java
Core/src/main/resources/static/apple/**.p8
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import allchive.server.api.auth.service.LogOutUserUseCase;
import allchive.server.api.auth.service.TokenRefreshUseCase;
import allchive.server.api.auth.service.WithdrawUserUseCase;
import allchive.server.domain.domains.user.domain.enums.OauthProvider;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,12 +22,11 @@ public class AuthController {
private final TokenRefreshUseCase tokenRefreshUseCase;

@Operation(summary = "회원탈퇴를 합니다.")
@DeleteMapping("/withdrawal/{provider}")
@DeleteMapping("/withdrawal")
public void withDrawUser(
@PathVariable OauthProvider provider,
@RequestParam(required = false, name = "appleAccessToken", value = "")
String appleAccessToken) {
withdrawUserUseCase.execute(provider, appleAccessToken);
withdrawUserUseCase.execute(appleAccessToken);
}

@Operation(summary = "로그아웃을 합니다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import allchive.server.domain.domains.user.service.UserDomainService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@UseCase
@RequiredArgsConstructor
Expand All @@ -43,11 +44,12 @@ public class WithdrawUserUseCase {
private final ReportDomainService reportDomainService;
private final UserDomainService userDomainService;

public void execute(OauthProvider provider, String appleAccessToken) {
@Transactional
public void execute(String appleAccessToken) {
Long userId = SecurityUtil.getCurrentUserId();
User user = userAdaptor.findById(userId);
// oauth쪽 탈퇴
withdrawOauth(provider, appleAccessToken, user);
withdrawOauth(user.getOauthInfo().getProvider(), appleAccessToken, user);
// 우리쪽 탈퇴
withdrawService(userId, user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import allchive.server.core.annotation.Helper;
import allchive.server.core.dto.OIDCDecodePayload;
import allchive.server.core.error.exception.NoAppleAccessTokenException;
import allchive.server.core.properties.AppleOAuthProperties;
import allchive.server.domain.domains.user.domain.enums.OauthInfo;
import allchive.server.domain.domains.user.domain.enums.OauthProvider;
Expand Down Expand Up @@ -77,6 +78,9 @@ public OIDCDecodePayload getOIDCDecodePayload(String token) {

/** apple측 회원 탈퇴 * */
public void withdrawAppleOauthUser(String appleOAuthAccessToken) {
if (appleOAuthAccessToken == null) {
throw NoAppleAccessTokenException.EXCEPTION;
}
appleOAuthClient.revoke(
appleOAuthProperties.getClientId(), appleOAuthAccessToken, this.getClientSecret());
}
Expand All @@ -87,7 +91,7 @@ private String getClientSecret() {
appleOAuthProperties.getTeamId(),
appleOAuthProperties.getClientId(),
appleOAuthProperties.getKeyId(),
appleOAuthProperties.getKeyPath(),
appleOAuthProperties.getAuthKey(),
appleOAuthProperties.getBaseUrl());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public class KakaoOauthHelper {

/** link * */
public String getKaKaoOauthLink(String referer) {
// TODO : 프론트 콜백 URL 알아내면 바꾸기
return kakaoOauthProperties.getBaseUrl()
+ String.format(
KAKAO_OAUTH_QUERY_STRING,
Expand All @@ -44,7 +43,6 @@ public String getKaKaoOauthLinkDev() {

/** token * */
public KakaoTokenResponse getKakaoOauthToken(String code, String referer) {
// TODO : 프론트 콜백 URL 알아내면 바꾸기
return kakaoOauthClient.kakaoAuth(
kakaoOauthProperties.getClientId(),
referer + "kakao/callback",
Expand Down
12 changes: 2 additions & 10 deletions Core/src/main/java/allchive/server/core/error/GlobalErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,17 @@ public enum GlobalErrorCode implements BaseErrorCode {

/** Server 오류 * */
HTTP_MESSAGE_NOT_READABLE(BAD_REQUEST, "GLOBAL_400_1", "잘못된 형식의 값을 입력했습니다."),
EMPTY_PARAM_VALUE(BAD_REQUEST, "GLOBAL_400_2", "빈 파람 값을 입력했습니다."),
NO_APPLE_ACCESS_TOKEN(BAD_REQUEST, "GLOBAL_400_2", "애플 엑세스 토큰이 필요합니다."),
EMPTY_PARAM_VALUE(BAD_REQUEST, "GLOBAL_400_3", "빈 파람 값을 입력했습니다."),
_INTERNAL_SERVER_ERROR(INTERNAL_SERVER, "GLOBAL_500_1", "서버 오류. 관리자에게 문의 부탁드립니다."),
INVALID_OAUTH_PROVIDER(INTERNAL_SERVER, "GLOBAL_500_2", "지원하지 않는 OAuth Provider 입니다."),

SECURITY_CONTEXT_NOT_FOUND(INTERNAL_SERVER, "GLOBAL_500_3", "security context not found"),

/** 토큰 에러 * */
// TODO : 에러 코드 정렬
INVALID_TOKEN(UNAUTHORIZED, "AUTH_401_2", "올바르지 않은 토큰입니다."),
INVALID_ACCESS_TOKEN_ERROR(UNAUTHORIZED, "AUTH_401_4", "알맞은 accessToken 을 넣어주세요."),
EXPIRED_TOKEN(UNAUTHORIZED, "AUTH_401_3", "만료된 엑세스 토큰입니다"),
EXPIRED_REFRESH_TOKEN(UNAUTHORIZED, "AUTH_403_1", "인증 시간이 만료되었습니다. 재 로그인 해주세요."),
INVALID_AUTH_TOKEN(UNAUTHORIZED, "AUTH_401_2", "액세스 토큰이 유효하지 않습니다"),
INVALID_REFRESH_TOKEN(UNAUTHORIZED, "AUTH_401_4", "리프레시 토큰이 유효하지 않습니다"),
MISMATCH_REFRESH_TOKEN(UNAUTHORIZED, "AUTH_401_6", "리프레시 토큰의 유저 정보가 일치하지 않습니다"),
FORBIDDEN_ADMIN(FORBIDDEN, "AUTH_403_1", "권한이 부여되지 않은 사용자입니다"),
UNSUPPORTED_TOKEN(UNAUTHORIZED, "AUTH_401_7", "지원하지 않는 토큰입니다"),
INVALID_SIGNATURE(UNAUTHORIZED, "AUTH_401_8", "잘못된 JWT 서명입니다"),
NO_TOKEN(UNAUTHORIZED, "AUTH_401_1", "토큰이 존재하지 않습니다"),

/** Feign Client 오류 */
OTHER_SERVER_BAD_REQUEST(BAD_REQUEST, "FEIGN_400_1", "Other server bad request"),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package allchive.server.core.error.exception;


import allchive.server.core.error.BaseErrorException;
import allchive.server.core.error.GlobalErrorCode;

public class NoAppleAccessTokenException extends BaseErrorException {

public static final BaseErrorException EXCEPTION = new NoAppleAccessTokenException();

private NoAppleAccessTokenException() {
super(GlobalErrorCode.NO_APPLE_ACCESS_TOKEN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@
public class AppleOAuthProperties {
private String baseUrl;
private String clientId;
private String appClientId;
private String keyId;
private String redirectUrl;
private String teamId;
private String scope;
private String keyPath;
private String webCallbackUrl;
private String appstoreIssuer;
private String authKey;
}
7 changes: 2 additions & 5 deletions Core/src/main/resources/application-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ oauth:

apple:
baseUrl: ${APPLE_BASE_URL}
clientId: ${APPLE_CLIENT}
appClientId: ${APPLE_APP_CLIENT_ID}
clientId: ${APPLE_CLIENT_ID}
keyId: ${APPLE_KEY_ID}
redirectUrl: ${APPLE_REDIRECT}
teamId: ${APPLE_TEAM_ID}
scope: ${APPLE_SCOPE}
keyPath: ${APPLE_KEY_PATH}
webCallbackUrl: ${APPLE_WEB_CALLBACK}
appstoreIssuer: ${APPLE_APPSTORE_ISSUER}
authKey: ${APPLE_AUTH_KEY}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
Expand All @@ -19,18 +20,10 @@
import java.util.Date;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class AppleLoginUtil {
/**
* client_secret 생성 Apple Document URL ‣
* https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
*
* @return client_secret(jwt)
*/
public static String createClientSecret(
String teamId, String clientId, String keyId, String keyPath, String authUrl) {
String teamId, String clientId, String keyId, String authKey, String authUrl) {

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(keyId).build();
JWTClaimsSet claimsSet = new JWTClaimsSet();
Expand All @@ -44,7 +37,7 @@ public static String createClientSecret(

SignedJWT jwt = new SignedJWT(header, claimsSet);

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(readPrivateKey(keyPath));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(readPrivateKey(authKey));
try {
KeyFactory kf = KeyFactory.getInstance("EC");
ECPrivateKey ecPrivateKey = (ECPrivateKey) kf.generatePrivate(spec);
Expand All @@ -64,12 +57,10 @@ public static String createClientSecret(
*
* @return Private Key
*/
private static byte[] readPrivateKey(String keyPath) {

Resource resource = new ClassPathResource(keyPath);
private static byte[] readPrivateKey(String authKey) {
byte[] content = null;

try (InputStream keyInputStream = resource.getInputStream();
byte[] byteAuthKey = authKey.replace("((()))", "\n").getBytes();
try (InputStream keyInputStream = new ByteArrayInputStream(byteAuthKey);
InputStreamReader keyReader = new InputStreamReader(keyInputStream);
PemReader pemReader = new PemReader(keyReader)) {
PemObject pemObject = pemReader.readPemObject();
Expand Down
Loading