diff --git a/cakk-api/build.gradle b/cakk-api/build.gradle index ab8bfb49..3fe68ea5 100644 --- a/cakk-api/build.gradle +++ b/cakk-api/build.gradle @@ -1,8 +1,8 @@ description = "api module" dependencies { - implementation(project(':cakk-common')) - implementation(project(':cakk-domain')) + implementation project(':cakk-common') + implementation project(':cakk-domain') // basic implementation('org.springframework.boot:spring-boot-starter-web') diff --git a/cakk-client/build.gradle b/cakk-client/build.gradle new file mode 100644 index 00000000..6b1098b8 --- /dev/null +++ b/cakk-client/build.gradle @@ -0,0 +1,16 @@ +description = 'client module' + +dependencies { + implementation project(':cakk-common') + + implementation('org.springframework.boot:spring-boot-starter-web') + implementation('com.google.api-client:google-api-client-jackson2:2.2.0') + implementation('com.google.api-client:google-api-client:2.2.0') +} + +bootJar { + enabled = false +} +jar { + enabled = true +} diff --git a/cakk-client/src/main/java/com/cakk/client/config/RestClientConfig.java b/cakk-client/src/main/java/com/cakk/client/config/RestClientConfig.java new file mode 100644 index 00000000..88f397b4 --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/config/RestClientConfig.java @@ -0,0 +1,23 @@ +package com.cakk.client.config; + +import java.time.Duration; + +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestClient; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestClientConfig { + + @Bean + public RestClient restClient() { + RestTemplate restTemplate = new RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(10)) + .setReadTimeout(Duration.ofSeconds(5)) + .build(); + + return RestClient.create(restTemplate); + } +} diff --git a/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKey.java b/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKey.java new file mode 100644 index 00000000..982af548 --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKey.java @@ -0,0 +1,11 @@ +package com.cakk.client.vo; + +public record OidcPublicKey( + String kid, + String kty, + String alg, + String use, + String n, + String e +) { +} diff --git a/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKeyList.java b/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKeyList.java new file mode 100644 index 00000000..cc2fd7b3 --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/vo/OidcPublicKeyList.java @@ -0,0 +1,19 @@ +package com.cakk.client.vo; + +import static com.cakk.common.enums.ReturnCode.*; + +import java.util.List; + +import com.cakk.common.exception.CakkException; + +public record OidcPublicKeyList( + List keys +) { + + public OidcPublicKey getMatchedKey(String kid, String alg) { + return keys.stream() + .filter(key -> key.kid().equals(kid) && key.alg().equals(alg)) + .findAny() + .orElseThrow(() -> new CakkException(EXTERNAL_SERVER_ERROR)); + } +} diff --git a/cakk-client/src/main/java/com/cakk/client/web/AppleAuthClient.java b/cakk-client/src/main/java/com/cakk/client/web/AppleAuthClient.java new file mode 100644 index 00000000..d1c0f17b --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/web/AppleAuthClient.java @@ -0,0 +1,26 @@ +package com.cakk.client.web; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClient; + +import lombok.RequiredArgsConstructor; + +import com.cakk.client.vo.OidcPublicKeyList; + +@Component +@RequiredArgsConstructor +public class AppleAuthClient { + + private final RestClient restClient; + + @Value("${oauth.apple.public-key-url}") + private final String publicKeyUrl; + + public OidcPublicKeyList getPublicKeys() { + return restClient.get() + .uri(publicKeyUrl) + .retrieve() + .body(OidcPublicKeyList.class); + } +} diff --git a/cakk-client/src/main/java/com/cakk/client/web/GoogleAuthConfiguration.java b/cakk-client/src/main/java/com/cakk/client/web/GoogleAuthConfiguration.java new file mode 100644 index 00000000..71494ad1 --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/web/GoogleAuthConfiguration.java @@ -0,0 +1,29 @@ +package com.cakk.client.web; + +import java.util.Collections; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; + +import lombok.RequiredArgsConstructor; + +@Configuration +@RequiredArgsConstructor +public class GoogleAuthConfiguration { + + @Value("${oauth.google.client-id}") + private String googleClientId; + + @Bean + public GoogleIdTokenVerifier googleIdTokenVerifier() { + return new GoogleIdTokenVerifier + .Builder(new NetHttpTransport(), new GsonFactory()) + .setAudience(Collections.singletonList(googleClientId)) + .build(); + } +} diff --git a/cakk-client/src/main/java/com/cakk/client/web/KakaoAuthClient.java b/cakk-client/src/main/java/com/cakk/client/web/KakaoAuthClient.java new file mode 100644 index 00000000..3ae11372 --- /dev/null +++ b/cakk-client/src/main/java/com/cakk/client/web/KakaoAuthClient.java @@ -0,0 +1,26 @@ +package com.cakk.client.web; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClient; + +import lombok.RequiredArgsConstructor; + +import com.cakk.client.vo.OidcPublicKeyList; + +@Component +@RequiredArgsConstructor +public class KakaoAuthClient { + + private final RestClient restClient; + + @Value("${oauth.kakao.public-key-url}") + private final String publicKeyUrl; + + public OidcPublicKeyList getPublicKeys() { + return restClient.get() + .uri(publicKeyUrl) + .retrieve() + .body(OidcPublicKeyList.class); + } +} diff --git a/cakk-client/src/main/resources/client-local.yml b/cakk-client/src/main/resources/client-local.yml new file mode 100644 index 00000000..9bb8694a --- /dev/null +++ b/cakk-client/src/main/resources/client-local.yml @@ -0,0 +1,7 @@ +oauth: + kakao: + public-key-info: https://kauth.kakao.com/.well-known/jwks.json + apple: + public-key-url: https://appleid.apple.com/auth/keys + google: + client-id: ${GOOGLE_CLIENT_ID} diff --git a/cakk-common/src/main/java/com/cakk/common/enums/ReturnCode.java b/cakk-common/src/main/java/com/cakk/common/enums/ReturnCode.java index 42963837..989ef3bd 100644 --- a/cakk-common/src/main/java/com/cakk/common/enums/ReturnCode.java +++ b/cakk-common/src/main/java/com/cakk/common/enums/ReturnCode.java @@ -7,7 +7,11 @@ @RequiredArgsConstructor public enum ReturnCode { - SUCCESS("1000", "요청에 성공하셨습니다."); + SUCCESS("1000", "요청에 성공하셨습니다."), + + // 서버 에러 (9998, 9999) + INTERNAL_SERVER_ERROR("9998", "내부 서버 에러 입니다."), + EXTERNAL_SERVER_ERROR("9999", "외부 서버 에러 입니다."); private final String code; private final String message; diff --git a/cakk-domain/build.gradle b/cakk-domain/build.gradle index e8cd537a..d5320fe4 100644 --- a/cakk-domain/build.gradle +++ b/cakk-domain/build.gradle @@ -1,7 +1,7 @@ description = "domain module" dependencies { - implementation(project(':cakk-common')) + implementation project(':cakk-common') // jpa implementation 'org.springframework.boot:spring-boot-starter-data-jpa' diff --git a/cakk-domain/src/main/java/com/cakk/domain/entity/user/User.java b/cakk-domain/src/main/java/com/cakk/domain/entity/user/User.java index 8f8bba91..560c5060 100644 --- a/cakk-domain/src/main/java/com/cakk/domain/entity/user/User.java +++ b/cakk-domain/src/main/java/com/cakk/domain/entity/user/User.java @@ -45,7 +45,10 @@ public class User extends AuditEntity { @Column(name = "nickname", length = 20, nullable = false) private String nickname; - @Column(name = "email", length = 20, nullable = false) + @Column(name = "profile_image_url", length = 200) + private String profileImageUrl; + + @Column(name = "email", length = 50, nullable = false) private String email; @Enumerated(value = EnumType.STRING) @@ -68,6 +71,7 @@ public User( Provider provider, String providerId, String nickname, + String profileImageUrl, String email, Gender gender, LocalDate birthday, @@ -76,6 +80,7 @@ public User( this.provider = provider; this.providerId = providerId; this.nickname = nickname; + this.profileImageUrl = profileImageUrl; this.email = email; this.gender = gender; this.birthday = birthday; diff --git a/settings.gradle b/settings.gradle index 91302cbc..8f49223a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,8 @@ rootProject.name = 'cakk' include( - 'cakk-api', - 'cakk-domain', - 'cakk-common' + 'cakk-api', + 'cakk-client', + 'cakk-domain', + 'cakk-common' )