From 6baeaedc652752f3b1d368fd1e146755cc73e710 Mon Sep 17 00:00:00 2001 From: minsu20 Date: Sat, 4 Nov 2023 22:30:09 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=ED=83=88=ED=87=B4?= =?UTF-8?q?=20API=20=EC=97=B0=EB=8F=99=ED=95=98=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/SignInUserCase.java | 2 +- .../application/service/WithdrawProvider.java | 7 ++ .../service/apple/AppleSignInUserCase.java | 2 +- .../service/apple/AppleTokenUserCase.java | 10 +- .../service/apple/AppleWithdrawUserCase.java | 95 +++++++++++++++++++ .../service/apple/feign/AppleFeignClient.java | 17 ---- .../service/apple/utils/AppleClient.java | 17 ++++ .../service/apple/utils/AppleToken.java | 47 +++++++++ .../apple/{feign/response => utils}/Keys.java | 2 +- .../service/google/GoogleSignInUserCase.java | 6 +- .../service/google/GoogleTokenUserCase.java | 2 +- .../google/GoogleWithdrawUserCase.java | 20 ++++ .../service/google/utils/GoogleClient.java | 12 +++ .../service/kakao/KakaoSignInUserCase.java | 2 +- .../service/kakao/KakaoTokenUserCase.java | 2 +- .../service/kakao/KakaoWithdrawUserCase.java | 20 ++++ .../service/kakao/utils/KakaoClient.java | 12 +++ .../kakao/utils/KakaoUnlinkResponse.java | 8 ++ .../dto/request/WithdrawRequest.java | 3 + .../application/service/WithdrawUserCase.java | 17 +++- .../mypage/presentation/MyPageController.java | 9 +- .../global/util/FeignClientConfig.java | 7 ++ 22 files changed, 282 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/WithdrawProvider.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java delete mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/AppleFeignClient.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleClient.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleToken.java rename src/main/java/com/moing/backend/domain/auth/application/service/apple/{feign/response => utils}/Keys.java (96%) create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleWithdrawUserCase.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/google/utils/GoogleClient.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoWithdrawUserCase.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoClient.java create mode 100644 src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoUnlinkResponse.java create mode 100644 src/main/java/com/moing/backend/global/util/FeignClientConfig.java diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/SignInUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/SignInUserCase.java index 9f4fb63f..205bfbd1 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/SignInUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/SignInUserCase.java @@ -40,7 +40,7 @@ public SignInResponse signIn(SignInRequest signInRequest, String providerInfo) { } private Member getUserDataFromPlatform(String accessToken, String providerInfo) { - SignInProvider signInProvider = signInProviders.get(providerInfo); + SignInProvider signInProvider = signInProviders.get(providerInfo+"SignIn"); if (signInProvider == null) { throw new IllegalArgumentException("Unknown provider: " + providerInfo); } diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/WithdrawProvider.java b/src/main/java/com/moing/backend/domain/auth/application/service/WithdrawProvider.java new file mode 100644 index 00000000..b67996b0 --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/WithdrawProvider.java @@ -0,0 +1,7 @@ +package com.moing.backend.domain.auth.application.service; + +import java.io.IOException; + +public interface WithdrawProvider { + void withdraw(String token) throws IOException; +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleSignInUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleSignInUserCase.java index 2f512ee2..05b1f179 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleSignInUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleSignInUserCase.java @@ -8,7 +8,7 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; -@Service("apple") +@Service("appleSignIn") @AllArgsConstructor public class AppleSignInUserCase implements SignInProvider { diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java index 945f5250..1b2826c1 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java @@ -1,7 +1,7 @@ package com.moing.backend.domain.auth.application.service.apple; -import com.moing.backend.domain.auth.application.service.apple.feign.AppleFeignClient; -import com.moing.backend.domain.auth.application.service.apple.feign.response.Keys; +import com.moing.backend.domain.auth.application.service.apple.utils.AppleClient; +import com.moing.backend.domain.auth.application.service.apple.utils.Keys; import com.moing.backend.domain.auth.exception.TokenInvalidException; import com.moing.backend.global.exception.InternalServerErrorException; import io.jsonwebtoken.*; @@ -21,10 +21,10 @@ @RequiredArgsConstructor public class AppleTokenUserCase { - @Value("${app-id.apple}") + @Value("${oauth2.apple.teamId}") private String appId; - private final AppleFeignClient appleFeignClient; + private final AppleClient appleClient; public Jws sigVerificationAndGetJws(String unverifiedToken) { @@ -34,7 +34,7 @@ public Jws sigVerificationAndGetJws(String unverifiedToken) { "https://appleid.apple.com", appId); - Keys keys = appleFeignClient.getKeys(); + Keys keys = appleClient.getKeys(); Keys.PubKey pubKey = keys.getKeys().stream() .filter((key) -> key.getKid().equals(kid)) .findAny() diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java new file mode 100644 index 00000000..645c6e4a --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java @@ -0,0 +1,95 @@ +package com.moing.backend.domain.auth.application.service.apple; + +import com.moing.backend.domain.auth.application.service.WithdrawProvider; +import com.moing.backend.domain.auth.application.service.apple.utils.AppleClient; +import com.moing.backend.domain.auth.application.service.apple.utils.AppleToken; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.RequiredArgsConstructor; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.security.Key; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Service("appleWithdraw") +@RequiredArgsConstructor +public class AppleWithdrawUserCase implements WithdrawProvider { + + @Value("${oauth2.apple.keyId}") + private String keyId; + + @Value("${oauth2.apple.teamId}") + private String teamId; + + @Value("${oauth2.apple.clientId}") + private String clientId; + + @Value("${oauth2.apple.keyPath}") + private String keyPath; + + private final AppleClient appleClient; + + public void withdraw(String token) throws IOException { + AppleToken.Response response = generateAuthToken(token); + + if (response.getAccess_token() != null) { + appleClient.revoke(AppleToken.RevokeRequest.of( + clientId, + createClientSecret(), + response.getAccess_token() + ) + ); + } + } + + public AppleToken.Response generateAuthToken(String authorizationCode) throws IOException { + + return appleClient.getToken(AppleToken.Request.of( + authorizationCode, + clientId, + createClientSecret(), + "authorization_code" + )); + } + + public String createClientSecret() throws IOException { + Date expirationDate = Date.from(LocalDateTime.now().plusDays(30).atZone(ZoneId.systemDefault()).toInstant()); + Map jwtHeader = new HashMap<>(); + jwtHeader.put("kid", keyId); + jwtHeader.put("alg", "ES256"); + + return Jwts.builder() + .setHeaderParams(jwtHeader) + .setIssuer(teamId) // Apple Developer 페이지에 명시되어 있는 Team ID (우측 상단에 있음) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(expirationDate) + .setAudience("https://appleid.apple.com") + .setSubject(clientId) // Apple Developer 페이지에 App Bundle ID (com.xxx.xxx 형식) + .signWith(getPrivateKey(), SignatureAlgorithm.ES256) + .compact(); + } + + private Key getPrivateKey() throws IOException { + ClassPathResource resource = new ClassPathResource(keyPath); + String privateKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); + + Reader pemReader = new StringReader(privateKey); + PEMParser pemParser = new PEMParser(pemReader); + JcaPEMKeyConverter converter = new JcaPEMKeyConverter(); + PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject(); + return converter.getPrivateKey(object); + } +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/AppleFeignClient.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/AppleFeignClient.java deleted file mode 100644 index 2c230bdc..00000000 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/AppleFeignClient.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.moing.backend.domain.auth.application.service.apple.feign; - -import com.moing.backend.domain.auth.application.service.apple.feign.response.Keys; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; - -@FeignClient(name = "appleClient", url = "https://appleid.apple.com/auth") -public interface AppleFeignClient { - - @Cacheable(cacheNames = "appleOICD", cacheManager = "oidcCacheManager") - @GetMapping(value = "/keys") - Keys getKeys(); - - @GetMapping(value = "/token") - String getAccessToken(); -} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleClient.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleClient.java new file mode 100644 index 00000000..de75629d --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleClient.java @@ -0,0 +1,17 @@ +package com.moing.backend.domain.auth.application.service.apple.utils; + +import com.moing.backend.global.util.FeignClientConfig; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +@FeignClient(name = "appleClient", url = "https://appleid.apple.com/auth", configuration = FeignClientConfig.class) +public interface AppleClient { + @GetMapping(value = "/keys") + Keys getKeys(); + @PostMapping(value = "/token", consumes = "application/x-www-form-urlencoded") + AppleToken.Response getToken(AppleToken.Request request); + + @PostMapping(value = "/revoke", consumes = "application/x-www-form-urlencoded") + void revoke(AppleToken.RevokeRequest request); +} \ No newline at end of file diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleToken.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleToken.java new file mode 100644 index 00000000..2fabd74a --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/AppleToken.java @@ -0,0 +1,47 @@ +package com.moing.backend.domain.auth.application.service.apple.utils; + +import lombok.Getter; + +public class AppleToken { + + public static class Request { + private String code; + private String client_id; + private String client_secret; + private String grant_type; + + public static Request of(String code, String clientId, String clientSecret, String grantType) { + Request request = new Request(); + request.code = code; + request.client_id = clientId; + request.client_secret = clientSecret; + request.grant_type = grantType; + return request; + } + } + + @Getter + public static class Response { + private String access_token; + private String expires_in; + private String id_token; + private String refresh_token; + private String token_type; + private String error; + } + + @Getter + public static class RevokeRequest { + private String client_id; + private String client_secret; + private String token; + + public static RevokeRequest of(String clientId, String clientSecret, String token) { + RevokeRequest request = new RevokeRequest(); + request.client_id = clientId; + request.client_secret = clientSecret; + request.token = token; + return request; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/response/Keys.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/Keys.java similarity index 96% rename from src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/response/Keys.java rename to src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/Keys.java index 2741263b..9261d011 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/feign/response/Keys.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/utils/Keys.java @@ -1,4 +1,4 @@ -package com.moing.backend.domain.auth.application.service.apple.feign.response; +package com.moing.backend.domain.auth.application.service.apple.utils; import lombok.Data; diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleSignInUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleSignInUserCase.java index 9dac6637..13c452d9 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleSignInUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleSignInUserCase.java @@ -2,21 +2,17 @@ import com.moing.backend.domain.auth.application.dto.response.GoogleUserResponse; import com.moing.backend.domain.auth.application.service.SignInProvider; -import com.moing.backend.domain.auth.exception.AppIdInvalidException; import com.moing.backend.domain.auth.exception.TokenInvalidException; import com.moing.backend.domain.member.application.mapper.MemberMapper; import com.moing.backend.domain.member.domain.entity.Member; import com.moing.backend.global.exception.InternalServerErrorException; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; -import java.util.Arrays; - -@Service("google") +@Service("googleSignIn") @RequiredArgsConstructor public class GoogleSignInUserCase implements SignInProvider { diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleTokenUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleTokenUserCase.java index 167889f3..b61cf800 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleTokenUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleTokenUserCase.java @@ -12,7 +12,7 @@ @RequiredArgsConstructor public class GoogleTokenUserCase { - @Value("${app-id.google}") + @Value("${oauth2.google.appId}") private String appId; public void verifyAccessToken(String aud) { diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleWithdrawUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleWithdrawUserCase.java new file mode 100644 index 00000000..7fddb5b9 --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/google/GoogleWithdrawUserCase.java @@ -0,0 +1,20 @@ +package com.moing.backend.domain.auth.application.service.google; + +import com.moing.backend.domain.auth.application.service.WithdrawProvider; +import com.moing.backend.domain.auth.application.service.google.utils.GoogleClient; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.IOException; + +@Service("googleWithdraw") +@RequiredArgsConstructor +public class GoogleWithdrawUserCase implements WithdrawProvider { + + private final GoogleClient googleClient; + + public void withdraw(String token) throws IOException { + googleClient.revoke(token); + } + +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/google/utils/GoogleClient.java b/src/main/java/com/moing/backend/domain/auth/application/service/google/utils/GoogleClient.java new file mode 100644 index 00000000..dd83003c --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/google/utils/GoogleClient.java @@ -0,0 +1,12 @@ +package com.moing.backend.domain.auth.application.service.google.utils; + +import com.moing.backend.global.util.FeignClientConfig; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = "googleClient", url = "https://oauth2.googleapis.com", configuration = FeignClientConfig.class) +public interface GoogleClient { + @PostMapping(value = "/revoke", consumes = "application/x-www-form-urlencoded") + void revoke(@RequestParam("token") String token); +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoSignInUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoSignInUserCase.java index 77b163d0..ef939b37 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoSignInUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoSignInUserCase.java @@ -12,7 +12,7 @@ import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; -@Service("kakao") +@Service("kakaoSignIn") @RequiredArgsConstructor public class KakaoSignInUserCase implements SignInProvider { diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoTokenUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoTokenUserCase.java index 09a7dbea..8f6d3766 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoTokenUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoTokenUserCase.java @@ -15,7 +15,7 @@ @RequiredArgsConstructor public class KakaoTokenUserCase { - @Value("${app-id.kakao}") + @Value("${oauth2.kakao.appId}") private String appId; private final WebClient webClient; diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoWithdrawUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoWithdrawUserCase.java new file mode 100644 index 00000000..f4525ba7 --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/KakaoWithdrawUserCase.java @@ -0,0 +1,20 @@ +package com.moing.backend.domain.auth.application.service.kakao; + +import com.moing.backend.domain.auth.application.service.WithdrawProvider; +import com.moing.backend.domain.auth.application.service.kakao.utils.KakaoClient; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.IOException; + +@Service("kakaoWithdraw") +@RequiredArgsConstructor +public class KakaoWithdrawUserCase implements WithdrawProvider { + + private final KakaoClient kakaoClient; + + public void withdraw(String token) throws IOException { + + kakaoClient.unlinkUser("Bearer " + token); + } +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoClient.java b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoClient.java new file mode 100644 index 00000000..a02b0d21 --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoClient.java @@ -0,0 +1,12 @@ +package com.moing.backend.domain.auth.application.service.kakao.utils; + +import com.moing.backend.global.util.FeignClientConfig; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; + +@FeignClient(name = "kakaoClient", url = "https://kapi.kakao.com", configuration = FeignClientConfig.class) +public interface KakaoClient { + @PostMapping("/v1/user/unlink") + KakaoUnlinkResponse unlinkUser(@RequestHeader("Authorization") String accessToken); +} diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoUnlinkResponse.java b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoUnlinkResponse.java new file mode 100644 index 00000000..de0e8333 --- /dev/null +++ b/src/main/java/com/moing/backend/domain/auth/application/service/kakao/utils/KakaoUnlinkResponse.java @@ -0,0 +1,8 @@ +package com.moing.backend.domain.auth.application.service.kakao.utils; + +import lombok.Getter; + +@Getter +public class KakaoUnlinkResponse { + private String id; +} diff --git a/src/main/java/com/moing/backend/domain/mypage/application/dto/request/WithdrawRequest.java b/src/main/java/com/moing/backend/domain/mypage/application/dto/request/WithdrawRequest.java index 78067857..1b07d726 100644 --- a/src/main/java/com/moing/backend/domain/mypage/application/dto/request/WithdrawRequest.java +++ b/src/main/java/com/moing/backend/domain/mypage/application/dto/request/WithdrawRequest.java @@ -16,4 +16,7 @@ public class WithdrawRequest { @NotBlank(message = "reason 을 입력해주세요.") @Size(min = 1, max = 500, message="reason 은 최소 1개, 최대 500개의 문자만 입력 가능합니다.") private String reason; + + @NotBlank(message = "socialToken 을 입력해주세요.") + private String socialToken; } diff --git a/src/main/java/com/moing/backend/domain/mypage/application/service/WithdrawUserCase.java b/src/main/java/com/moing/backend/domain/mypage/application/service/WithdrawUserCase.java index 4a0dbf16..df959b27 100644 --- a/src/main/java/com/moing/backend/domain/mypage/application/service/WithdrawUserCase.java +++ b/src/main/java/com/moing/backend/domain/mypage/application/service/WithdrawUserCase.java @@ -1,5 +1,7 @@ package com.moing.backend.domain.mypage.application.service; +import com.moing.backend.domain.auth.application.service.SignInProvider; +import com.moing.backend.domain.auth.application.service.WithdrawProvider; import com.moing.backend.domain.member.domain.entity.Member; import com.moing.backend.domain.member.domain.service.MemberDeleteService; import com.moing.backend.domain.member.domain.service.MemberGetService; @@ -11,6 +13,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.util.Map; + @Service @RequiredArgsConstructor public class WithdrawUserCase { @@ -20,15 +25,25 @@ public class WithdrawUserCase { private final TokenUtil tokenUtil; private final MemberDeleteService memberDeleteService; private final TeamMemberGetService teamMemberGetService; + private final Map withdrawProviders; - public void withdraw(String socialId, WithdrawRequest withdrawRequest) { + public void withdraw(String socialId, String providerInfo, WithdrawRequest withdrawRequest) throws IOException { Member member = memberGetService.getMemberBySocialId(socialId); checkMemberIsNotPartOfAnyTeam(member); + withdraw(providerInfo, withdrawRequest.getSocialToken()); memberDeleteService.deleteMember(member); feedbackSaveService.saveFeedback(member, withdrawRequest); tokenUtil.expireRefreshToken(socialId); } + private void withdraw(String providerInfo, String token) throws IOException { + WithdrawProvider withdrawProvider=withdrawProviders.get(providerInfo+"Withdraw"); + if (withdrawProvider == null) { + throw new IllegalArgumentException("Unknown provider: " + providerInfo); + } + withdrawProvider.withdraw(token); + } + private void checkMemberIsNotPartOfAnyTeam(Member member) { if (!teamMemberGetService.getNotDeletedTeamMember(member.getMemberId()).isEmpty()) { throw new ExistingTeamException(); diff --git a/src/main/java/com/moing/backend/domain/mypage/presentation/MyPageController.java b/src/main/java/com/moing/backend/domain/mypage/presentation/MyPageController.java index daeb6ffb..deb82e9b 100644 --- a/src/main/java/com/moing/backend/domain/mypage/presentation/MyPageController.java +++ b/src/main/java/com/moing/backend/domain/mypage/presentation/MyPageController.java @@ -15,6 +15,8 @@ import javax.validation.Valid; +import java.io.IOException; + import static com.moing.backend.domain.mypage.presentation.constant.MypageResponseMessage.*; @RestController @@ -44,10 +46,11 @@ public ResponseEntity signOut(@AuthenticationPrincipal User use * [DELETE] api/mypage/withdrawal * 작성자 : 김민수 */ - @DeleteMapping("/withdrawal") + @DeleteMapping("/withdrawal/{provider}") public ResponseEntity withdraw(@AuthenticationPrincipal User user, - @Valid @RequestBody WithdrawRequest withdrawRequest) { - this.withdrawService.withdraw(user.getSocialId(), withdrawRequest); + @PathVariable String provider, + @Valid @RequestBody WithdrawRequest withdrawRequest) throws IOException { + this.withdrawService.withdraw(user.getSocialId(), provider, withdrawRequest); return ResponseEntity.ok(SuccessResponse.create(WITHDRAWAL_SUCCESS.getMessage())); } diff --git a/src/main/java/com/moing/backend/global/util/FeignClientConfig.java b/src/main/java/com/moing/backend/global/util/FeignClientConfig.java new file mode 100644 index 00000000..a9b6bd75 --- /dev/null +++ b/src/main/java/com/moing/backend/global/util/FeignClientConfig.java @@ -0,0 +1,7 @@ +package com.moing.backend.global.util; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FeignClientConfig { +} \ No newline at end of file From 10495de5e59fb39d0059ec2bc1c0e1351c735e2b Mon Sep 17 00:00:00 2001 From: minsu20 Date: Sun, 5 Nov 2023 11:21:27 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=ED=9A=8C=EC=9B=90=ED=83=88=ED=87=B4?= =?UTF-8?q?=20API=20=EB=AA=85=EC=84=B8=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/Mypage-API.adoc | 2 +- .../mypage/presentation/MypageControllerTest.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/docs/asciidoc/Mypage-API.adoc b/src/docs/asciidoc/Mypage-API.adoc index b5b9e9c8..76317426 100644 --- a/src/docs/asciidoc/Mypage-API.adoc +++ b/src/docs/asciidoc/Mypage-API.adoc @@ -9,7 +9,7 @@ operation::mypage-controller-test/sign_out[snippets='http-request,http-response, [[Mypage-회원탈퇴]] == Mypage 회원탈퇴 -operation::mypage-controller-test/withdraw[snippets='http-request,request-fields,http-response,response-fields'] +operation::mypage-controller-test/withdraw[snippets='path-parameters,http-request,request-fields,http-response,response-fields'] [[Mypage-전체-조회]] == Mypage 전체 조회 diff --git a/src/test/java/com/moing/backend/domain/mypage/presentation/MypageControllerTest.java b/src/test/java/com/moing/backend/domain/mypage/presentation/MypageControllerTest.java index d8364020..0e811495 100644 --- a/src/test/java/com/moing/backend/domain/mypage/presentation/MypageControllerTest.java +++ b/src/test/java/com/moing/backend/domain/mypage/presentation/MypageControllerTest.java @@ -13,6 +13,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.web.servlet.ResultActions; import java.util.ArrayList; @@ -23,8 +24,7 @@ import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.payload.PayloadDocumentation.*; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.restdocs.request.RequestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -76,14 +76,15 @@ public void withdraw() throws Exception { //given WithdrawRequest input = WithdrawRequest.builder() .reason("REASON_TO_LEAVE") + .socialToken("SOCIAL_TOKEN") .build(); String body = objectMapper.writeValueAsString(input); //when - ResultActions actions = mockMvc.perform( - delete("/api/mypage/withdrawal") + ResultActions actions = mockMvc.perform(RestDocumentationRequestBuilders. + delete("/api/mypage/withdrawal/{provider}","google,kakao,apple") .header("Authorization", "Bearer ACCESS_TOKEN") .contentType(MediaType.APPLICATION_JSON) .content(body) @@ -98,7 +99,11 @@ public void withdraw() throws Exception { requestHeaders( headerWithName("Authorization").description("접근 토큰") ), + pathParameters( + parameterWithName("provider").description("google, kakao, apple") + ), requestFields( + fieldWithPath("socialToken").description("google:accessToken/ kakao:accessToken/ apple:authorization code"), fieldWithPath("reason").description("회원탈퇴하는 이유") ), responseFields( From 1a5fec0bd883f07da120515a34cd8e053b074771 Mon Sep 17 00:00:00 2001 From: minsu20 Date: Mon, 6 Nov 2023 20:10:22 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/service/apple/AppleTokenUserCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java index 1b2826c1..20d9218d 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleTokenUserCase.java @@ -21,7 +21,7 @@ @RequiredArgsConstructor public class AppleTokenUserCase { - @Value("${oauth2.apple.teamId}") + @Value("${oauth2.apple.clientId}") private String appId; private final AppleClient appleClient; From 284f7ac9ca596ea5cb2d095b3f4c8c3f3e7597d2 Mon Sep 17 00:00:00 2001 From: minsu20 Date: Mon, 6 Nov 2023 20:18:29 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=EC=93=B8=EB=AA=A8=EC=97=86=EB=8A=94?= =?UTF-8?q?=20=EC=A3=BC=EC=84=9D=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/application/service/apple/AppleWithdrawUserCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java index 645c6e4a..910519a3 100644 --- a/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java +++ b/src/main/java/com/moing/backend/domain/auth/application/service/apple/AppleWithdrawUserCase.java @@ -73,11 +73,11 @@ public String createClientSecret() throws IOException { return Jwts.builder() .setHeaderParams(jwtHeader) - .setIssuer(teamId) // Apple Developer 페이지에 명시되어 있는 Team ID (우측 상단에 있음) + .setIssuer(teamId) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(expirationDate) .setAudience("https://appleid.apple.com") - .setSubject(clientId) // Apple Developer 페이지에 App Bundle ID (com.xxx.xxx 형식) + .setSubject(clientId) .signWith(getPrivateKey(), SignatureAlgorithm.ES256) .compact(); }