From fe102fc153fa5504123822ec031c0d0b118bc6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sat, 4 Jan 2025 16:40:06 +0900 Subject: [PATCH 01/47] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/auth/dto/request/LoginRequest.kt | 5 +++++ .../site/yourevents/auth/dto/response/LoginResponse.kt | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 module-presentation/src/main/kotlin/site/yourevents/auth/dto/request/LoginRequest.kt create mode 100644 module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/request/LoginRequest.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/request/LoginRequest.kt new file mode 100644 index 0000000..b53933f --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/request/LoginRequest.kt @@ -0,0 +1,5 @@ +package site.yourevents.auth.dto.request + +data class LoginRequest( + val code: String, +) diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt new file mode 100644 index 0000000..937ca2e --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt @@ -0,0 +1,9 @@ +package site.yourevents.auth.dto.response + +import java.util.UUID + +data class LoginResponse( + val userId: UUID, + val nickname: String, + val accessToken: String, +) From 27218508e5e70eecaaca0b470a0ff33b62d14cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sat, 4 Jan 2025 16:41:23 +0900 Subject: [PATCH 02/47] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/type/SuccessCode.kt | 1 + .../site/yourevents/auth/api/AuthApi.kt | 12 +++++++++++ .../yourevents/auth/api/AuthController.kt | 20 +++++++++++++++++++ .../site/yourevents/auth/facade/AuthFacade.kt | 14 +++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthApi.kt create mode 100644 module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt create mode 100644 module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt diff --git a/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt b/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt index 658e84f..bfa7774 100644 --- a/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt +++ b/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt @@ -6,4 +6,5 @@ enum class SuccessCode( val message: String, ) { REQUEST_OK(200, "OK", "요청이 성공적으로 처리되었습니다."), + LOGIN_SUCCESS(201, "LOGIN_SUCCESS", "소셜 로그인이 정상적으로 처리되었습니다."), } diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthApi.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthApi.kt new file mode 100644 index 0000000..6437f5a --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthApi.kt @@ -0,0 +1,12 @@ +package site.yourevents.auth.api + +import io.swagger.v3.oas.annotations.Operation +import org.springframework.web.bind.annotation.RequestBody +import site.yourevents.auth.dto.request.LoginRequest +import site.yourevents.auth.dto.response.LoginResponse +import site.yourevents.response.ApiResponse + +interface AuthApi { + @Operation(summary = "카카오 소셜 로그인") + fun login(@RequestBody request: LoginRequest): ApiResponse +} diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt new file mode 100644 index 0000000..d4411b8 --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt @@ -0,0 +1,20 @@ +package site.yourevents.auth.api + +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RestController +import site.yourevents.auth.dto.request.LoginRequest +import site.yourevents.auth.dto.response.LoginResponse +import site.yourevents.auth.facade.AuthFacade +import site.yourevents.response.ApiResponse +import site.yourevents.type.SuccessCode + +@RestController +class AuthController( + private val authFacade: AuthFacade +) : AuthApi { + @PostMapping("/login") + override fun login(request: LoginRequest): ApiResponse { + return ApiResponse.success(SuccessCode.LOGIN_SUCCESS, authFacade.login(request)) + } + +} \ No newline at end of file diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt new file mode 100644 index 0000000..4a5f983 --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt @@ -0,0 +1,14 @@ +package site.yourevents.auth.facade + +import org.springframework.stereotype.Service +import site.yourevents.auth.dto.request.LoginRequest +import site.yourevents.auth.dto.response.LoginResponse + +@Service +class AuthFacade( + +) { + fun login(request: LoginRequest): LoginResponse { + return TODO("소셜 로그인 구현") + } +} \ No newline at end of file From d3677b27eb10a95143ebbc16d8fde0c364f16d2a Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:05:39 +0900 Subject: [PATCH 03/47] =?UTF-8?q?fix:=20Docker=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=EA=B0=80=20=EB=B9=8C=EB=93=9C=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EB=AA=BB=ED=95=98=EB=8A=94=20=EC=98=A4=EB=A5=98=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 - Spring Application의 BootJar 생성 후 빌드 된 파일을 Dockerfile에 명시된 위치로 이동하도록 변경 --- module-presentation/build.gradle.kts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/module-presentation/build.gradle.kts b/module-presentation/build.gradle.kts index 8229781..7a97dca 100644 --- a/module-presentation/build.gradle.kts +++ b/module-presentation/build.gradle.kts @@ -2,6 +2,7 @@ import org.springframework.boot.gradle.tasks.bundling.BootJar val jar: Jar by tasks val bootJar: BootJar by tasks +val jarName = "app.jar" bootJar.enabled = true jar.enabled = false @@ -25,3 +26,14 @@ dependencies { tasks.getByName("bootJar") { mainClass.set("site.yourevents.YourEventsApplicationKt") } + +tasks.named("bootJar") { + archiveFileName.set(jarName) + + doLast { + copy { + from("build/libs/$jarName") + into("../build/libs") + } + } +} From 182b8d1ceeabb9e5ad350188aca34a30036561df Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 00:57:06 +0900 Subject: [PATCH 04/47] =?UTF-8?q?feat:=20=EB=AA=A8=EB=8B=88=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=EB=AA=A8=EB=93=88=20=EC=83=9D=EC=84=B1=20=EB=B0=8F?= =?UTF-8?q?=20Sentry=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/build.gradle.kts | 18 ++++++++++++++++++ settings.gradle.kts | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 module-infrastructure/monitoring/build.gradle.kts diff --git a/module-infrastructure/monitoring/build.gradle.kts b/module-infrastructure/monitoring/build.gradle.kts new file mode 100644 index 0000000..54c774f --- /dev/null +++ b/module-infrastructure/monitoring/build.gradle.kts @@ -0,0 +1,18 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +val jar: Jar by tasks +val bootJar: BootJar by tasks + +bootJar.enabled = false +jar.enabled = true + +plugins { + kotlin("plugin.jpa") version "2.1.0" +} + +dependencies { + + // Sentry + api("io.sentry:sentry-logback:7.17.0") + api("com.github.maricn:logback-slack-appender:1.6.1") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 81a0392..61c0d5e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,7 +5,8 @@ include("module-presentation") include("module-domain") include("module-infrastructure") +include("module-infrastructure:security") +include("module-infrastructure:monitoring") include("module-infrastructure:persistence-db") include("module-independent") -include("module-infrastructure:security") From 3371d8f219562c70f01bde14cade82dd040cd89e Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 01:07:08 +0900 Subject: [PATCH 05/47] =?UTF-8?q?feat:=20Sentry=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/sentry/SentryConfig.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt diff --git a/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt b/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt new file mode 100644 index 0000000..36a485d --- /dev/null +++ b/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt @@ -0,0 +1,22 @@ +package site.yourevents.sentry + +import io.sentry.Sentry +import jakarta.annotation.PostConstruct +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Configuration + +@Configuration +class SentryConfig( + @Value("\${sentry.dsn}") private val sentryDsn: String, + @Value("\${sentry.environment}") private val environment: String, + @Value("\${sentry.servername}") private val serverName: String +) { + @PostConstruct + fun initSentry() { + Sentry.init { options -> + options.dsn = sentryDsn + options.environment = environment + options.serverName = serverName + } + } +} From 7c936fa233f6cb9180fd32fa16e6f963c06d5578 Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 01:12:24 +0900 Subject: [PATCH 06/47] =?UTF-8?q?chore:=20Sentry=20WebHook=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/console-appender.xml | 8 +++ .../src/main/resources/logback-spring.xml | 53 +++++++++++++++++++ module-presentation/build.gradle.kts | 1 + 3 files changed, 62 insertions(+) create mode 100644 module-infrastructure/monitoring/src/main/resources/console-appender.xml create mode 100644 module-infrastructure/monitoring/src/main/resources/logback-spring.xml diff --git a/module-infrastructure/monitoring/src/main/resources/console-appender.xml b/module-infrastructure/monitoring/src/main/resources/console-appender.xml new file mode 100644 index 0000000..8f23ce1 --- /dev/null +++ b/module-infrastructure/monitoring/src/main/resources/console-appender.xml @@ -0,0 +1,8 @@ + + + + ${LOG_PATTERN} + + + diff --git a/module-infrastructure/monitoring/src/main/resources/logback-spring.xml b/module-infrastructure/monitoring/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..ca92a21 --- /dev/null +++ b/module-infrastructure/monitoring/src/main/resources/logback-spring.xml @@ -0,0 +1,53 @@ + + + + + + always + true + 1.0 + ERROR + DEBUG + + + + + + + ${SLACK_WEBHOOK_URI} + + *🚨[${ENVIRONMENT}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread] %-5level %class - %msg <${SENTRY_REPOSITORY_URI}|Go-To-Sentry>* + %n + + + Error-Bot + :robot_face: + true + + + + + ERROR + + + + + + + + + + + + + + + + + + + + + + diff --git a/module-presentation/build.gradle.kts b/module-presentation/build.gradle.kts index 7a97dca..79bb9c3 100644 --- a/module-presentation/build.gradle.kts +++ b/module-presentation/build.gradle.kts @@ -9,6 +9,7 @@ jar.enabled = false dependencies { implementation(project(":module-domain")) + implementation(project(":module-infrastructure:monitoring")) implementation(project(":module-infrastructure:persistence-db")) implementation(project(":module-independent")) From bbaae57915866f49c6738dc5c20acd4d5f91347f Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 01:17:19 +0900 Subject: [PATCH 07/47] =?UTF-8?q?chore:=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 외부 모듈에서 의존성을 사용할 수 없도록 변경 --- module-infrastructure/monitoring/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module-infrastructure/monitoring/build.gradle.kts b/module-infrastructure/monitoring/build.gradle.kts index 54c774f..525d837 100644 --- a/module-infrastructure/monitoring/build.gradle.kts +++ b/module-infrastructure/monitoring/build.gradle.kts @@ -13,6 +13,6 @@ plugins { dependencies { // Sentry - api("io.sentry:sentry-logback:7.17.0") - api("com.github.maricn:logback-slack-appender:1.6.1") + implementation("io.sentry:sentry-logback:7.17.0") + implementation("com.github.maricn:logback-slack-appender:1.6.1") } From e3f62c29aea1a6daac3974d4841756cc110d9e6f Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 01:21:30 +0900 Subject: [PATCH 08/47] =?UTF-8?q?chore:=20Sentry=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=ED=94=84=EB=A1=9C=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 13 +++++++++++++ .../src/main/resources/application-local.yml | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/module-presentation/src/main/resources/application-dev.yml b/module-presentation/src/main/resources/application-dev.yml index 5450302..cd1811a 100644 --- a/module-presentation/src/main/resources/application-dev.yml +++ b/module-presentation/src/main/resources/application-dev.yml @@ -17,3 +17,16 @@ spring: app: server: url: ENC(uN3Diby1cLKgQIKPznbuLr/9mQrqzUFhTlzKRp4ZCSxovF26NNCo+A==) + +sentry: + dsn: ENC(UefOk3EHvOlzQ+99rApWCWoEMEbTlVbECMRxnRLgtNzuWJa0PmWL1pBtfGRpRK6qWsOSGlmWlJsP7PI7JVaLOnHG3CDLM2bChy61gXTkqYiTs2I1Axf8SW/rxMmcEkH7PLOqEY/TI5I= + environment: ENC(5Nbdf/7y1sF9NAU0jw0SCg==) + servername: ENC(Tf/+6HqlCb8m17xkhfHjhw==) + +logging: + config: classpath:logback-spring.xml + sentry: + repository-uri: ENC(g0Krw6t6uRDttMcJbvX50G2tfUmi+5R+jH6C40Q6Je2kLfCArJNWdSG/YBoIq0+E1zsJamVrVfqG3tOgLWqPMppT9zVlHC60z4Mw9VrXPBFzaZrkXDb+UnAL+WggMg2SzzN0iapM7xo=) + environment: ENC(GWw5mEHTRfd0Ngg/p8uZ7Q==) + slack: + webhook-url: ENC(2V14VMxtr6ga6VYnVumgqqYDdzRfcUzO0+QXJl26W0bfHoVW7APdzecmMuA6/KWENMB3M1SFw5bqwOsI0hdYtzOX6aKicOBAadZ1ESN8fcPsB7b5GaTI1TI/wUdMjTEc) diff --git a/module-presentation/src/main/resources/application-local.yml b/module-presentation/src/main/resources/application-local.yml index cb960b2..3adfc67 100644 --- a/module-presentation/src/main/resources/application-local.yml +++ b/module-presentation/src/main/resources/application-local.yml @@ -17,3 +17,16 @@ spring: app: server: url: http://localhost:8080 + +sentry: + dsn: ENC(p3USktYJhoxYtz0GFLCVpu4fki0u0eN424zqg6rE3vKH5DjjWfqFRN+Enj/rLkCFAhYwlwFtT++KW62gqtm1CnnHxeJfrAki+FdAnWO3JRj29aXea/N8xrE7h/MoZ58Tapyi+wWH5eM=) + environment: ENC(FVBHvqTsvv2ytyUnt6i2lw==) + servername: ENC(cGNqcZ4YnA0ufysvNrAyVzDz1/w6/vUi) + +logging: + config: classpath:logback-spring.xml + sentry: + repository-uri: ENC(Ql7eE0mWdzUcjepLC2Eq7e2PyXyNaG0V2onethHlafhcJ5t9pLBZmeroj3+vkM9zp88YIwxcvMks69YZrEeXBT0MX7C028pAJsxCM54G+wF/uXclw0xOXM9DgWaEkBheAuav6C5Mwqg=) + environment: ENC(qaAYY+h/ALoN3KDILvoV+g==) + slack: + webhook-url: ENC(WHEGoh730wj5KIl+MTr2LTifDVemTwX9+LimiJRRsEnynVGHb7ev0jqY55Su8FfeX6IAh17LRa6NeM42h/tJFR1trqv0iflQZFDKi0/l+VSGBhTBg39s4K0O1bjmeEHN) From e7846206c31facb6b3bde8a2af8de32fe4e246d3 Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:35:25 +0900 Subject: [PATCH 09/47] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=94=8C=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-infrastructure/monitoring/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/module-infrastructure/monitoring/build.gradle.kts b/module-infrastructure/monitoring/build.gradle.kts index 525d837..6801a20 100644 --- a/module-infrastructure/monitoring/build.gradle.kts +++ b/module-infrastructure/monitoring/build.gradle.kts @@ -6,10 +6,6 @@ val bootJar: BootJar by tasks bootJar.enabled = false jar.enabled = true -plugins { - kotlin("plugin.jpa") version "2.1.0" -} - dependencies { // Sentry From 70954fc4c3e333746bfd49d91130b8c5da8ee52f Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:37:31 +0900 Subject: [PATCH 10/47] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/sentry/SentryConfig.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt b/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt index 36a485d..24d41aa 100644 --- a/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt +++ b/module-infrastructure/monitoring/src/main/kotlin/site/yourevents/sentry/SentryConfig.kt @@ -7,9 +7,14 @@ import org.springframework.context.annotation.Configuration @Configuration class SentryConfig( - @Value("\${sentry.dsn}") private val sentryDsn: String, - @Value("\${sentry.environment}") private val environment: String, - @Value("\${sentry.servername}") private val serverName: String + @Value("\${sentry.dsn}") + private val sentryDsn: String, + + @Value("\${sentry.environment}") + private val environment: String, + + @Value("\${sentry.servername}") + private val serverName: String ) { @PostConstruct fun initSentry() { From 3631cc6e09fbe8cdc5b1c9fadaaccdc5a63f2517 Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:23:06 +0900 Subject: [PATCH 11/47] =?UTF-8?q?fix:=20`.xml`=EC=97=90=EC=84=9C=20Jasypt?= =?UTF-8?q?=20=EC=95=94=ED=98=B8=ED=99=94=EB=A5=BC=20=EC=9D=B8=EC=8B=9D?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EB=AA=BB=ED=95=98=EB=8A=94=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-presentation/src/main/resources/application-dev.yml | 6 +++--- .../src/main/resources/application-local.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/module-presentation/src/main/resources/application-dev.yml b/module-presentation/src/main/resources/application-dev.yml index cd1811a..4d951bb 100644 --- a/module-presentation/src/main/resources/application-dev.yml +++ b/module-presentation/src/main/resources/application-dev.yml @@ -26,7 +26,7 @@ sentry: logging: config: classpath:logback-spring.xml sentry: - repository-uri: ENC(g0Krw6t6uRDttMcJbvX50G2tfUmi+5R+jH6C40Q6Je2kLfCArJNWdSG/YBoIq0+E1zsJamVrVfqG3tOgLWqPMppT9zVlHC60z4Mw9VrXPBFzaZrkXDb+UnAL+WggMg2SzzN0iapM7xo=) - environment: ENC(GWw5mEHTRfd0Ngg/p8uZ7Q==) + repository-uri: ${SENTRY_REPOSITORY_URI} + environment: ${SENTRY_ENVIRONMENT} slack: - webhook-url: ENC(2V14VMxtr6ga6VYnVumgqqYDdzRfcUzO0+QXJl26W0bfHoVW7APdzecmMuA6/KWENMB3M1SFw5bqwOsI0hdYtzOX6aKicOBAadZ1ESN8fcPsB7b5GaTI1TI/wUdMjTEc) + webhook-url: ${SLACK_WEBHOOK_URL} diff --git a/module-presentation/src/main/resources/application-local.yml b/module-presentation/src/main/resources/application-local.yml index 3adfc67..86f4e0f 100644 --- a/module-presentation/src/main/resources/application-local.yml +++ b/module-presentation/src/main/resources/application-local.yml @@ -26,7 +26,7 @@ sentry: logging: config: classpath:logback-spring.xml sentry: - repository-uri: ENC(Ql7eE0mWdzUcjepLC2Eq7e2PyXyNaG0V2onethHlafhcJ5t9pLBZmeroj3+vkM9zp88YIwxcvMks69YZrEeXBT0MX7C028pAJsxCM54G+wF/uXclw0xOXM9DgWaEkBheAuav6C5Mwqg=) - environment: ENC(qaAYY+h/ALoN3KDILvoV+g==) + repository-uri: ${SENTRY_REPOSITORY_URI} + environment: ${SENTRY_ENVIRONMENT} slack: - webhook-url: ENC(WHEGoh730wj5KIl+MTr2LTifDVemTwX9+LimiJRRsEnynVGHb7ev0jqY55Su8FfeX6IAh17LRa6NeM42h/tJFR1trqv0iflQZFDKi0/l+VSGBhTBg39s4K0O1bjmeEHN) + webhook-url: ${SLACK_WEBHOOK_URL} From ccad504f95d1f421108d6ebf0824b97417d30012 Mon Sep 17 00:00:00 2001 From: yechan-kim <60172300+yechan-kim@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:29:54 +0900 Subject: [PATCH 12/47] =?UTF-8?q?chore:=20local=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EC=97=90=EC=84=9C=20Sentry=20=EB=B0=8F=20WebHook=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/src/main/resources/logback-spring.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module-infrastructure/monitoring/src/main/resources/logback-spring.xml b/module-infrastructure/monitoring/src/main/resources/logback-spring.xml index ca92a21..c7ea001 100644 --- a/module-infrastructure/monitoring/src/main/resources/logback-spring.xml +++ b/module-infrastructure/monitoring/src/main/resources/logback-spring.xml @@ -36,8 +36,8 @@ - - + + From 747599a057c477fe51c6c4e72b67526b333a0378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sun, 5 Jan 2025 23:12:44 +0900 Subject: [PATCH 13/47] =?UTF-8?q?feat:=20JWT=20Utils=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20Jwt=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81,=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EB=A1=9C=EC=A7=81,=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filter/JwtAuthenticationEntryPoint.kt | 30 +++++ .../filter/JwtAuthorizationFilter.kt | 44 +++++++ .../kotlin/site/yourevents/jwt/JwtProvider.kt | 114 ++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt new file mode 100644 index 0000000..f18d628 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt @@ -0,0 +1,30 @@ +package site.yourevents.filter + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.jetbrains.annotations.NotNull +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import org.springframework.stereotype.Component +import site.yourevents.response.ApiResponse +import site.yourevents.type.ErrorCode + +@Component +class JwtAuthenticationEntryPoint : AuthenticationEntryPoint { + override fun commence( + @NotNull request: HttpServletRequest, + @NotNull response: HttpServletResponse, + @NotNull authException: AuthenticationException + ) { + response.contentType = "application/json;charset=UTF-8" + response.status = HttpServletResponse.SC_UNAUTHORIZED + + val mapper = ObjectMapper() + val jsonResponse: String = mapper.writeValueAsString( + ApiResponse.error(ErrorCode.EMPTY_AUTHENTICATION) + ) + + response.writer.write(jsonResponse) + } +} \ No newline at end of file diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt new file mode 100644 index 0000000..c1eae4e --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt @@ -0,0 +1,44 @@ +package site.yourevents.filter + +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.jetbrains.annotations.NotNull +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter +import site.yourevents.jwt.JwtProvider + +@Component +class JwtAuthorizationFilter( + private val jwtProvider: JwtProvider +) : OncePerRequestFilter() { + companion object { + private const val HEADER_PREFIX: String = "Authorization" + private const val TOKEN_PREFIX: String = "Bearer " + } + + override fun doFilterInternal( + @NotNull request: HttpServletRequest, + @NotNull response: HttpServletResponse, + @NotNull filterChain: FilterChain + ) { + val accessToken: String? = extractToken(request) + + if (null != accessToken) { + val authentication: Authentication = jwtProvider.getAuthentication(accessToken) + SecurityContextHolder.getContext().authentication = authentication + } + filterChain.doFilter(request, response) + } + + private fun extractToken(request: HttpServletRequest): String? { + val authorizationHeader: String = request.getHeader(HEADER_PREFIX) + + if (authorizationHeader.startsWith(TOKEN_PREFIX)) { + return authorizationHeader.substringAfter(TOKEN_PREFIX) + } + return null + } +} \ No newline at end of file diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt new file mode 100644 index 0000000..7e1588d --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -0,0 +1,114 @@ +package site.yourevents.jwt + +import io.jsonwebtoken.Claims +import io.jsonwebtoken.ExpiredJwtException +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.MalformedJwtException +import io.jsonwebtoken.UnsupportedJwtException +import org.springframework.beans.factory.annotation.Value +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.stereotype.Service +import site.yourevents.jwt.exception.ExpiredTokenException +import site.yourevents.jwt.exception.InvalidTokenException +import site.yourevents.jwt.exception.MalformedTokenException +import site.yourevents.jwt.exception.UnsupportedTokenException +import site.yourevents.principal.AuthDetails +import site.yourevents.service.AuthDetailsService +import java.util.Base64 +import java.util.Collections +import java.util.Date +import java.util.UUID +import javax.crypto.spec.SecretKeySpec +import kotlin.time.Duration +import kotlin.time.Duration.Companion.days + +@Service +class JwtProvider( + @Value("\${jwt.secret_key}") + private val secret: String, + private val authDetailsService: AuthDetailsService, +) { + companion object { + private val ACCESS_TOKEN_DURATION: Duration = 7.days + } + + private val secretKey: SecretKeySpec + get() { + val keyBytes: ByteArray = Base64.getDecoder().decode(secret) + return SecretKeySpec(keyBytes, "HmacSHA256") + } + + fun generateAccessToken(memberId: UUID, email: String, role: String): String { + return generateToken(memberId, email, ACCESS_TOKEN_DURATION, role) + } + + private fun generateToken( + memberId: UUID, + email: String, + duration: Duration, + role: String + ): String { + val now = Date() + val expiry = Date(now.time + duration.inWholeMilliseconds) + + return Jwts.builder() + .subject(email) + .claim("id", memberId) + .claim("role", role) + .expiration(expiry) + .signWith(secretKey) + .compact() + } + + fun getAuthentication(token: String) : Authentication { + val claims = validateToken(token) + val authorities: Collection? = Collections.singletonList( + SimpleGrantedAuthority(claims["role"].toString()) + ) + + return UsernamePasswordAuthenticationToken(getAuthDetails(claims), "", authorities) + } + + private fun extractAllClaims(token: String): Claims { + return Jwts.parser() + .verifyWith(secretKey) + .build() + .parseSignedClaims(token) + .getPayload() + } + + fun getAuthDetails(claims: Claims): AuthDetails { + return authDetailsService.loadUserByUsername(claims.subject) + } + + private fun validateToken(token: String): Claims { + try { + return extractAllClaims(token) + } catch (e: IllegalArgumentException) { + throw InvalidTokenException() + } catch (e: ExpiredJwtException) { + throw ExpiredTokenException() + } catch (e: MalformedJwtException) { + throw MalformedTokenException() + } catch (e: UnsupportedJwtException) { + throw UnsupportedTokenException() + } + } + + fun isInvalidToken(token: String): Boolean { + return runCatching { validateToken(token) } + .onFailure { e -> + if (e is InvalidTokenException || + e is ExpiredTokenException || + e is MalformedTokenException || + e is UnsupportedTokenException + ) { + return true + } + } + .isFailure + } +} From 641d23e60ac9cd7ce7968e36bd26a74925c7e441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sun, 5 Jan 2025 23:13:08 +0900 Subject: [PATCH 14/47] =?UTF-8?q?feat:=20JWT=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/error/exception/ServiceException.kt | 2 +- .../site/yourevents/jwt/exception/ExpiredTokenException.kt | 6 ++++++ .../site/yourevents/jwt/exception/InvalidTokenException.kt | 6 ++++++ .../yourevents/jwt/exception/MalformedTokenException.kt | 6 ++++++ .../yourevents/jwt/exception/UnsupportedTokenException.kt | 6 ++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/ExpiredTokenException.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/InvalidTokenException.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/MalformedTokenException.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/UnsupportedTokenException.kt diff --git a/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt b/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt index 7ad6be1..05710c5 100644 --- a/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt +++ b/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt @@ -2,7 +2,7 @@ package site.yourevents.error.exception import site.yourevents.type.ErrorCode -class ServiceException( +open class ServiceException( private val errorCode: ErrorCode ) : RuntimeException() { } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/ExpiredTokenException.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/ExpiredTokenException.kt new file mode 100644 index 0000000..87524bd --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/ExpiredTokenException.kt @@ -0,0 +1,6 @@ +package site.yourevents.jwt.exception + +import site.yourevents.error.exception.ServiceException +import site.yourevents.type.ErrorCode + +class ExpiredTokenException : ServiceException(ErrorCode.EXPIRED_TOKEN) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/InvalidTokenException.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/InvalidTokenException.kt new file mode 100644 index 0000000..11e4a65 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/InvalidTokenException.kt @@ -0,0 +1,6 @@ +package site.yourevents.jwt.exception + +import site.yourevents.error.exception.ServiceException +import site.yourevents.type.ErrorCode + +class InvalidTokenException : ServiceException(ErrorCode.INVALID_TOKEN) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/MalformedTokenException.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/MalformedTokenException.kt new file mode 100644 index 0000000..67d2077 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/MalformedTokenException.kt @@ -0,0 +1,6 @@ +package site.yourevents.jwt.exception + +import site.yourevents.error.exception.ServiceException +import site.yourevents.type.ErrorCode + +class MalformedTokenException : ServiceException(ErrorCode.MALFORMED_TOKEN) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/UnsupportedTokenException.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/UnsupportedTokenException.kt new file mode 100644 index 0000000..82d0046 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/exception/UnsupportedTokenException.kt @@ -0,0 +1,6 @@ +package site.yourevents.jwt.exception + +import site.yourevents.error.exception.ServiceException +import site.yourevents.type.ErrorCode + +class UnsupportedTokenException : ServiceException(ErrorCode.UNSUPPORTED_TOKEN) From b814427aa531e412aa4128f317de5f4c51b25dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sun, 5 Jan 2025 23:14:13 +0900 Subject: [PATCH 15/47] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/build.gradle.kts | 3 +++ .../site/yourevents/principal/AuthDetails.kt | 25 +++++++++++++++++++ .../yourevents/service/AuthDetailsService.kt | 16 ++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt diff --git a/module-infrastructure/security/build.gradle.kts b/module-infrastructure/security/build.gradle.kts index 51fb208..bcb3511 100644 --- a/module-infrastructure/security/build.gradle.kts +++ b/module-infrastructure/security/build.gradle.kts @@ -7,6 +7,9 @@ bootJar.enabled = false jar.enabled = true dependencies { + implementation(project(":module-independent")) + implementation(project(":module-domain")) + //Spring Security implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-web") diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt new file mode 100644 index 0000000..98b0785 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt @@ -0,0 +1,25 @@ +package site.yourevents.principal + +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.UserDetails +import java.util.Collections +import java.util.UUID + +class AuthDetails( + private val uuid: UUID, + private val email: String, + private val role: String, +) : UserDetails { + override fun getAuthorities(): Collection? { + return Collections.singletonList(SimpleGrantedAuthority("ROLE_USER")) + } + + override fun getPassword(): String? { + return null + } + + override fun getUsername(): String? { + return email + } +} \ No newline at end of file diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt new file mode 100644 index 0000000..4a9f813 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt @@ -0,0 +1,16 @@ +package site.yourevents.service + +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.stereotype.Service +import site.yourevents.member.port.`in`.MemberUseCase +import site.yourevents.principal.AuthDetails + +@Service +class AuthDetailsService( + private val memberUseCase: MemberUseCase +) : UserDetailsService { + override fun loadUserByUsername(email: String): AuthDetails { + val member = memberUseCase.findByEmail(email) + return AuthDetails(member.getId(), member.getNickname(), "ROLE_USER") + } +} From 731122ef562bb24f82bc7f24f5fa4da67ab5ceb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Mon, 6 Jan 2025 13:51:25 +0900 Subject: [PATCH 16/47] =?UTF-8?q?feat:=20Member=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20<->=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=A7=A4?= =?UTF-8?q?=ED=95=91=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/member/Member.kt | 6 ++++- .../yourevents/member/entity/MemberEntity.kt | 23 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/member/Member.kt b/module-domain/src/main/kotlin/site/yourevents/member/Member.kt index b199495..bd79f59 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/Member.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/Member.kt @@ -5,7 +5,11 @@ import java.util.UUID class Member( private val id: UUID, private val nickname: String, - private val socialId: String, private val email: String, ) { + fun getId(): UUID = id + + fun getNickname(): String = nickname + + fun getEmail(): String = email } diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt index cf63c52..784bbe7 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt @@ -5,6 +5,7 @@ import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType import jakarta.persistence.Id +import site.yourevents.member.Member import java.util.UUID @Entity(name = "member") @@ -16,10 +17,24 @@ class MemberEntity( @Column private val nickname: String, - @Column - private val socialId: String, - @Column private val email: String, ) { -} \ No newline at end of file + fun toDomain(): Member { + return Member( + id = id, + nickname = nickname, + email = email, + ) + } + + companion object { + fun from(member: Member): MemberEntity { + return MemberEntity( + id = member.getId(), + nickname = member.getNickname(), + email = member.getEmail(), + ) + } + } +} From 11f2f9e40339ed0f977f90a802e9c5b2a391ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Mon, 6 Jan 2025 13:51:52 +0900 Subject: [PATCH 17/47] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=EC=9D=84=20=ED=86=B5=ED=95=9C=20=EB=A9=A4=EB=B2=84=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/member/port/in/MemberUseCase.kt | 7 +++++++ .../out/persistence/MemberPersistencePort.kt | 7 +++++++ .../yourevents/member/service/MemberService.kt | 15 +++++++++++++++ .../member/repository/MemberJPARepository.kt | 10 ++++++++++ .../member/repository/MemberRepository.kt | 18 ++++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt create mode 100644 module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt create mode 100644 module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt new file mode 100644 index 0000000..b788535 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt @@ -0,0 +1,7 @@ +package site.yourevents.member.port.`in` + +import site.yourevents.member.Member + +interface MemberUseCase { + fun findByEmail(email: String): Member +} diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt new file mode 100644 index 0000000..35f9712 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt @@ -0,0 +1,7 @@ +package site.yourevents.member.port.out.persistence + +import site.yourevents.member.Member + +interface MemberPersistencePort { + fun findByEmail(email: String): Member +} diff --git a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt new file mode 100644 index 0000000..12a6beb --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt @@ -0,0 +1,15 @@ +package site.yourevents.member.service + +import org.springframework.stereotype.Service +import site.yourevents.member.Member +import site.yourevents.member.port.`in`.MemberUseCase +import site.yourevents.member.port.out.persistence.MemberPersistencePort + +@Service +class MemberService( + private val memberPersistencePort: MemberPersistencePort +) : MemberUseCase { + override fun findByEmail(email: String): Member { + return memberPersistencePort.findByEmail(email) + } +} \ No newline at end of file diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt new file mode 100644 index 0000000..417c9bf --- /dev/null +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt @@ -0,0 +1,10 @@ +package site.yourevents.member.repository + +import org.springframework.data.jpa.repository.JpaRepository +import site.yourevents.member.entity.MemberEntity +import java.util.Optional +import java.util.UUID + +interface MemberJPARepository : JpaRepository { + fun findByEmail(email: String): Optional +} diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt new file mode 100644 index 0000000..9ec514c --- /dev/null +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt @@ -0,0 +1,18 @@ +package site.yourevents.member.repository + +import org.springframework.stereotype.Repository +import site.yourevents.member.Member +import site.yourevents.member.port.out.persistence.MemberPersistencePort +import kotlin.jvm.optionals.getOrNull + +@Repository +class MemberRepository( + private val memberJPARepository: MemberJPARepository +) : MemberPersistencePort { + override fun findByEmail(email: String): Member { + return memberJPARepository.findByEmail(email) + .getOrNull() + ?.toDomain() + ?: throw IllegalArgumentException() + } +} From c00f6440ad430f520bc354dc505d44feed4a2bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Mon, 6 Jan 2025 21:05:19 +0900 Subject: [PATCH 18/47] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=EC=9D=84=20=EC=9C=84=ED=95=9C=20VO,=20DTO=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/auth/vo/KakaoProfile.kt | 15 +++++++++++++ .../dto/response/KakaoAccessToken.kt | 16 ++++++++++++++ .../dto/response/KakaoProfileResponse.kt | 22 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt new file mode 100644 index 0000000..8a4a0af --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt @@ -0,0 +1,15 @@ +package site.yourevents.auth.vo + +data class KakaoProfile( + val nickname: String, + val email: String, +) { + companion object { + fun of( + nickname: String, + email: String + ): KakaoProfile { + return KakaoProfile(nickname, email) + } + } +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt new file mode 100644 index 0000000..749db10 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt @@ -0,0 +1,16 @@ +package site.yourevents.dto.response + +import com.google.gson.JsonParser + +data class KakaoAccessToken( + val accessToken: String +) { + companion object { + fun from(jsonResponseBody: String): KakaoAccessToken { + val response = JsonParser.parseString(jsonResponseBody).asJsonObject + val accessToken = response.get("access_token").asString + + return KakaoAccessToken(accessToken) + } + } +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt new file mode 100644 index 0000000..bf43684 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt @@ -0,0 +1,22 @@ +package site.yourevents.dto.response + +import com.google.gson.JsonObject +import com.google.gson.JsonParser + +data class KakaoProfileResponse( + val nickname: String, + val email: String, +) { + companion object { + fun from(jsonResponseBody: String): KakaoProfileResponse { + val jsonObject: JsonObject = + JsonParser.parseString(jsonResponseBody).asJsonObject + + val kakaoAccount: JsonObject = jsonObject.get("kakao_account").asJsonObject + val nickname: String = kakaoAccount.get("name").asString + val email: String = kakaoAccount.get("email").asString + + return KakaoProfileResponse(nickname, email) + } + } +} From 743b3ef16eb4f963b2ecf494ebc1e20eeda4c49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Mon, 6 Jan 2025 21:10:52 +0900 Subject: [PATCH 19/47] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-domain/build.gradle.kts | 8 ++ .../auth/port/in/usecase/AuthUseCase.kt | 7 ++ .../yourevents/auth/port/out/SocialPort.kt | 7 ++ .../yourevents/auth/service/AuthService.kt | 17 ++++ .../site/yourevents/auth/vo/KakaoProfile.kt | 4 +- .../security/build.gradle.kts | 3 + .../site/yourevents/service/SocialClient.kt | 77 +++++++++++++++++++ module-presentation/build.gradle.kts | 5 ++ 8 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/port/out/SocialPort.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt diff --git a/module-domain/build.gradle.kts b/module-domain/build.gradle.kts index 16270d9..fee181a 100644 --- a/module-domain/build.gradle.kts +++ b/module-domain/build.gradle.kts @@ -5,3 +5,11 @@ val bootJar: BootJar by tasks bootJar.enabled = false jar.enabled = true + +plugins { + kotlin("plugin.jpa") version "2.1.0" +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-data-jpa") +} diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt new file mode 100644 index 0000000..dbc2518 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt @@ -0,0 +1,7 @@ +package site.yourevents.auth.port.`in`.usecase + +import site.yourevents.auth.vo.KakaoProfile + +interface AuthUseCase { + fun getKakaoUserInfoFromCode(code: String): KakaoProfile +} \ No newline at end of file diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SocialPort.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SocialPort.kt new file mode 100644 index 0000000..041ff90 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SocialPort.kt @@ -0,0 +1,7 @@ +package site.yourevents.auth.port.out + +import site.yourevents.auth.vo.KakaoProfile + +interface SocialPort { + fun getKakaoUserInfoFromCode(code: String) : KakaoProfile +} diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt b/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt new file mode 100644 index 0000000..2c2d99a --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt @@ -0,0 +1,17 @@ +package site.yourevents.auth.service + +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import site.yourevents.auth.port.`in`.usecase.AuthUseCase +import site.yourevents.auth.port.out.SocialPort +import site.yourevents.auth.vo.KakaoProfile + +@Service +@Transactional +class AuthService( + private val socialPort: SocialPort +) : AuthUseCase { + override fun getKakaoUserInfoFromCode(code: String): KakaoProfile { + return socialPort.getKakaoUserInfoFromCode(code) + } +} diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt index 8a4a0af..66d6393 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt @@ -8,8 +8,6 @@ data class KakaoProfile( fun of( nickname: String, email: String - ): KakaoProfile { - return KakaoProfile(nickname, email) - } + ): KakaoProfile = KakaoProfile(nickname, email) } } diff --git a/module-infrastructure/security/build.gradle.kts b/module-infrastructure/security/build.gradle.kts index bcb3511..4723c2d 100644 --- a/module-infrastructure/security/build.gradle.kts +++ b/module-infrastructure/security/build.gradle.kts @@ -24,4 +24,7 @@ dependencies { // Spring Security Test testImplementation("org.springframework.security:spring-security-test") + + // JSON + implementation("com.google.code.gson:gson:2.11.0") } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt new file mode 100644 index 0000000..7173fcd --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt @@ -0,0 +1,77 @@ +package site.yourevents.service + +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Component +import org.springframework.util.LinkedMultiValueMap +import org.springframework.web.client.RestTemplate +import site.yourevents.auth.port.out.SocialPort +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.dto.response.KakaoProfileResponse +import site.yourevents.dto.response.KakaoAccessToken + +@Component +class SocialClient( + @Value("\${spring.security.oauth2.client.registration.kakao.client-id}") + private val clientId: String, + + @Value("\${spring.security.oauth2.client.registration.kakao.client-redirect-uri}") + private val redirectUri: String, + + @Value("\${spring.security.oauth2.client.registration.kakao.authorization-grant-type}") + private val grantType: String, + + @Value("\${spring.security.oauth2.client.provider.kakao.token-uri}") + private val tokenUri: String, + + @Value("\${spring.security.oauth2.client.provider.kakao.user-info-uri}") + private val userInfoUri: String, +) : SocialPort { + override fun getKakaoUserInfoFromCode(code: String): KakaoProfile { + val token: String = getKakaoAccessToken(code) + + return getKakaoUserInfoFromToken(token) + } + + private fun getKakaoAccessToken(code: String): String { + val restTemplate = RestTemplate() + + val headers = HttpHeaders().apply { + add("Content-type", "application/x-www-form-urlencoded;charset=utf-8") + } + + val body = LinkedMultiValueMap().apply { + add("grant_type", grantType) + add("client_id", clientId) + add("redirect_uri", redirectUri) + add("code", code) + } + + val tokenRequest = HttpEntity(body, headers) + + val response: ResponseEntity = + restTemplate.postForEntity(tokenUri, tokenRequest, String::class.java) + + return KakaoAccessToken.from(response.body!!).accessToken + } + + private fun getKakaoUserInfoFromToken(token: String): KakaoProfile { + val restTemplate = RestTemplate() + + val headers = HttpHeaders().apply { + add("Authorization", "Bearer $token") + add("Content-type", "application/x-www-form-urlencoded;charset=utf-8") + } + + val profileRequest = HttpEntity(null, headers) + + val response: ResponseEntity = + restTemplate.postForEntity(userInfoUri, profileRequest, String::class.java) + + val profileResponse = KakaoProfileResponse.from(response.body!!) + + return KakaoProfile.of(profileResponse.nickname, profileResponse.email) + } +} diff --git a/module-presentation/build.gradle.kts b/module-presentation/build.gradle.kts index 79bb9c3..c710ddc 100644 --- a/module-presentation/build.gradle.kts +++ b/module-presentation/build.gradle.kts @@ -7,6 +7,10 @@ val jarName = "app.jar" bootJar.enabled = true jar.enabled = false +plugins { + kotlin("plugin.jpa") version "2.1.0" +} + dependencies { implementation(project(":module-domain")) implementation(project(":module-infrastructure:monitoring")) @@ -15,6 +19,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-security") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") // Jasypt From 21748338c6e2ea9ef69640cbe86e2659593ca0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Mon, 6 Jan 2025 21:44:13 +0900 Subject: [PATCH 20/47] =?UTF-8?q?refactor:=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20Null=EC=9D=84=20Facade=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-domain/build.gradle.kts | 2 ++ .../yourevents/member/exception/MemberNotFountException.kt | 6 ++++++ .../kotlin/site/yourevents/member/port/in/MemberUseCase.kt | 2 +- .../member/port/out/persistence/MemberPersistencePort.kt | 2 +- .../kotlin/site/yourevents/member/service/MemberService.kt | 2 +- .../src/main/kotlin/site/yourevents/type/ErrorCode.kt | 5 +---- .../site/yourevents/member/repository/MemberRepository.kt | 6 ++---- .../kotlin/site/yourevents/service/AuthDetailsService.kt | 3 +++ 8 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 module-domain/src/main/kotlin/site/yourevents/member/exception/MemberNotFountException.kt diff --git a/module-domain/build.gradle.kts b/module-domain/build.gradle.kts index fee181a..b36b510 100644 --- a/module-domain/build.gradle.kts +++ b/module-domain/build.gradle.kts @@ -11,5 +11,7 @@ plugins { } dependencies { + implementation(project(":module-independent")) + implementation("org.springframework.boot:spring-boot-starter-data-jpa") } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/exception/MemberNotFountException.kt b/module-domain/src/main/kotlin/site/yourevents/member/exception/MemberNotFountException.kt new file mode 100644 index 0000000..6007e49 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/member/exception/MemberNotFountException.kt @@ -0,0 +1,6 @@ +package site.yourevents.member.exception + +import site.yourevents.error.exception.ServiceException +import site.yourevents.type.ErrorCode + +class MemberNotFountException : ServiceException(ErrorCode.MEMBER_NOT_FOUND) diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt index b788535..018602d 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt @@ -3,5 +3,5 @@ package site.yourevents.member.port.`in` import site.yourevents.member.Member interface MemberUseCase { - fun findByEmail(email: String): Member + fun findByEmail(email: String): Member? } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt index 35f9712..897a242 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt @@ -3,5 +3,5 @@ package site.yourevents.member.port.out.persistence import site.yourevents.member.Member interface MemberPersistencePort { - fun findByEmail(email: String): Member + fun findByEmail(email: String): Member? } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt index 12a6beb..1b0e784 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt @@ -9,7 +9,7 @@ import site.yourevents.member.port.out.persistence.MemberPersistencePort class MemberService( private val memberPersistencePort: MemberPersistencePort ) : MemberUseCase { - override fun findByEmail(email: String): Member { + override fun findByEmail(email: String): Member? { return memberPersistencePort.findByEmail(email) } } \ No newline at end of file diff --git a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt index db2974b..be1ef55 100644 --- a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt +++ b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt @@ -10,9 +10,6 @@ enum class ErrorCode( MALFORMED_TOKEN(401, "MALFORMED_TOKEN", "위/변조된 토큰입니다."), UNSUPPORTED_TOKEN(401, "UNSUPPORTED_TOKEN", "지원하지 않는 토큰입니다."), EMPTY_AUTHENTICATION(401, "EMPTY_AUTHENTICATION", "인증정보가 존재하지 않습니다."), - ROLE_FORBIDDEN(403, "ROLE_FORBIDDEN", "접근할 수 있는 권한이 아닙니다."), - PASSWORD_NOT_MATCH(403, "PASSWORD_NOT_MATCH", "비밀번호가 일치하지 않습니다."), - USER_NOT_FOUND(404, "USER_NOT_FOUND", "존재하지 않는 사용자입니다."), - ADMIN_NOT_FOUND(404, "ADMIN_NOT_FOUND", "존재하지 않는 관리자입니다."), + MEMBER_NOT_FOUND(404, "MEMBER_NOT_FOUND", "존재하지 않는 사용자입니다."), INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR", "서버 오류가 발생했습니다."), } \ No newline at end of file diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt index 9ec514c..6f38558 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt @@ -9,10 +9,8 @@ import kotlin.jvm.optionals.getOrNull class MemberRepository( private val memberJPARepository: MemberJPARepository ) : MemberPersistencePort { - override fun findByEmail(email: String): Member { + override fun findByEmail(email: String): Member? { return memberJPARepository.findByEmail(email) - .getOrNull() - ?.toDomain() - ?: throw IllegalArgumentException() + .getOrNull()?.toDomain() } } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt index 4a9f813..b979c4b 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt @@ -2,6 +2,7 @@ package site.yourevents.service import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.stereotype.Service +import site.yourevents.member.exception.MemberNotFountException import site.yourevents.member.port.`in`.MemberUseCase import site.yourevents.principal.AuthDetails @@ -11,6 +12,8 @@ class AuthDetailsService( ) : UserDetailsService { override fun loadUserByUsername(email: String): AuthDetails { val member = memberUseCase.findByEmail(email) + ?: throw MemberNotFountException() + return AuthDetails(member.getId(), member.getNickname(), "ROLE_USER") } } From 64679d39f3b028a0ff8828d65c745b8979218365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 13:51:45 +0900 Subject: [PATCH 21/47] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EB=A1=9C=EC=A7=81=20DI=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/port/in/usecase/TokenUseCase.kt | 7 +++++++ .../site/yourevents/auth/port/out/SecurityPort.kt | 7 +++++++ .../site/yourevents/auth/service/TokenService.kt | 15 +++++++++++++++ .../kotlin/site/yourevents/jwt/JwtProvider.kt | 7 ++++--- module-presentation/build.gradle.kts | 1 + .../yourevents/auth/dto/response/LoginResponse.kt | 10 +++++++++- 6 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt create mode 100644 module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt new file mode 100644 index 0000000..44ed674 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt @@ -0,0 +1,7 @@ +package site.yourevents.auth.port.`in`.usecase + +import java.util.UUID + +interface TokenUseCase { + fun generateAccessToken(id: UUID, email: String, role: String) : String +} diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt new file mode 100644 index 0000000..9dc0979 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt @@ -0,0 +1,7 @@ +package site.yourevents.auth.port.out + +import java.util.UUID + +interface SecurityPort { + fun generateAccessToken(id: UUID, email: String, role: String) : String +} diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt new file mode 100644 index 0000000..c0f5bf6 --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt @@ -0,0 +1,15 @@ +package site.yourevents.auth.service + +import org.springframework.stereotype.Service +import site.yourevents.auth.port.`in`.usecase.TokenUseCase +import site.yourevents.auth.port.out.SecurityPort +import java.util.UUID + +@Service +class TokenService( + private val securityPort: SecurityPort, +) : TokenUseCase { + override fun generateAccessToken(id: UUID, email: String, role: String): String { + return securityPort.generateAccessToken(id, email, role) + } +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt index 7e1588d..4d310d5 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -11,6 +11,7 @@ import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.stereotype.Service +import site.yourevents.auth.port.out.SecurityPort import site.yourevents.jwt.exception.ExpiredTokenException import site.yourevents.jwt.exception.InvalidTokenException import site.yourevents.jwt.exception.MalformedTokenException @@ -30,7 +31,7 @@ class JwtProvider( @Value("\${jwt.secret_key}") private val secret: String, private val authDetailsService: AuthDetailsService, -) { +) : SecurityPort { companion object { private val ACCESS_TOKEN_DURATION: Duration = 7.days } @@ -41,7 +42,7 @@ class JwtProvider( return SecretKeySpec(keyBytes, "HmacSHA256") } - fun generateAccessToken(memberId: UUID, email: String, role: String): String { + override fun generateAccessToken(memberId: UUID, email: String, role: String): String { return generateToken(memberId, email, ACCESS_TOKEN_DURATION, role) } @@ -111,4 +112,4 @@ class JwtProvider( } .isFailure } -} +} \ No newline at end of file diff --git a/module-presentation/build.gradle.kts b/module-presentation/build.gradle.kts index c710ddc..1832ace 100644 --- a/module-presentation/build.gradle.kts +++ b/module-presentation/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { implementation(project(":module-domain")) implementation(project(":module-infrastructure:monitoring")) implementation(project(":module-infrastructure:persistence-db")) + implementation(project(":module-infrastructure:security")) implementation(project(":module-independent")) implementation("org.springframework.boot:spring-boot-starter-web") diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt index 937ca2e..13968c5 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt @@ -6,4 +6,12 @@ data class LoginResponse( val userId: UUID, val nickname: String, val accessToken: String, -) +) { + companion object { + fun of( + userId: UUID, + nickname: String, + accessToken: String + ): LoginResponse = LoginResponse(userId, nickname, accessToken) + } +} From bc2ecc50bc8acbe759b2ceae48b986b324d3d12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 14:21:56 +0900 Subject: [PATCH 22/47] =?UTF-8?q?refactor:=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20VO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/invitation/Guest.kt | 2 +- .../site/yourevents/invitation/Invitation.kt | 2 +- .../site/yourevents/member/{ => domain}/Member.kt | 2 +- .../site/yourevents/member/domain/MemberVO.kt | 13 +++++++++++++ .../site/yourevents/member/entity/MemberEntity.kt | 14 +++++++------- 5 files changed, 23 insertions(+), 10 deletions(-) rename module-domain/src/main/kotlin/site/yourevents/member/{ => domain}/Member.kt (86%) create mode 100644 module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt diff --git a/module-domain/src/main/kotlin/site/yourevents/invitation/Guest.kt b/module-domain/src/main/kotlin/site/yourevents/invitation/Guest.kt index c14773f..f7ee528 100644 --- a/module-domain/src/main/kotlin/site/yourevents/invitation/Guest.kt +++ b/module-domain/src/main/kotlin/site/yourevents/invitation/Guest.kt @@ -1,6 +1,6 @@ package site.yourevents.invitation -import site.yourevents.member.Member +import site.yourevents.member.domain.Member import java.util.UUID class Guest( diff --git a/module-domain/src/main/kotlin/site/yourevents/invitation/Invitation.kt b/module-domain/src/main/kotlin/site/yourevents/invitation/Invitation.kt index 5efb42e..0f063bf 100644 --- a/module-domain/src/main/kotlin/site/yourevents/invitation/Invitation.kt +++ b/module-domain/src/main/kotlin/site/yourevents/invitation/Invitation.kt @@ -1,6 +1,6 @@ package site.yourevents.invitation -import site.yourevents.member.Member +import site.yourevents.member.domain.Member import java.util.UUID class Invitation( diff --git a/module-domain/src/main/kotlin/site/yourevents/member/Member.kt b/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt similarity index 86% rename from module-domain/src/main/kotlin/site/yourevents/member/Member.kt rename to module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt index bd79f59..bcdb3ae 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/Member.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt @@ -1,4 +1,4 @@ -package site.yourevents.member +package site.yourevents.member.domain import java.util.UUID diff --git a/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt b/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt new file mode 100644 index 0000000..c1232bd --- /dev/null +++ b/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt @@ -0,0 +1,13 @@ +package site.yourevents.member.domain + +import site.yourevents.auth.vo.KakaoProfile + +data class MemberVO( + val nickname: String, + val email: String, +) { + companion object { + fun from(kakaoProfile: KakaoProfile): MemberVO = + MemberVO(kakaoProfile.nickname, kakaoProfile.email) + } +} diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt index 784bbe7..0f2418c 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt @@ -5,14 +5,15 @@ import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType import jakarta.persistence.Id -import site.yourevents.member.Member +import site.yourevents.member.domain.Member +import site.yourevents.member.domain.MemberVO import java.util.UUID @Entity(name = "member") class MemberEntity( @Id @GeneratedValue(strategy = GenerationType.UUID) - private val id: UUID, + private val id: UUID? = null, @Column private val nickname: String, @@ -22,18 +23,17 @@ class MemberEntity( ) { fun toDomain(): Member { return Member( - id = id, + id = id!!, nickname = nickname, email = email, ) } companion object { - fun from(member: Member): MemberEntity { + fun from(memberVO: MemberVO): MemberEntity { return MemberEntity( - id = member.getId(), - nickname = member.getNickname(), - email = member.getEmail(), + nickname = memberVO.nickname, + email = memberVO.email, ) } } From 45cb7113ffe53c5814738679d883ee959edb2a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 14:34:34 +0900 Subject: [PATCH 23/47] =?UTF-8?q?feat:=20MemberVO=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/member/port/in/MemberUseCase.kt | 5 ++++- .../port/out/persistence/MemberPersistencePort.kt | 5 ++++- .../site/yourevents/member/service/MemberService.kt | 10 ++++++++-- .../yourevents/member/repository/MemberRepository.kt | 9 ++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt index 018602d..ce7092d 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt @@ -1,7 +1,10 @@ package site.yourevents.member.port.`in` -import site.yourevents.member.Member +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.member.domain.Member interface MemberUseCase { fun findByEmail(email: String): Member? + + fun createMember(kakaoProfile: KakaoProfile): Member } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt index 897a242..8b54c08 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt @@ -1,7 +1,10 @@ package site.yourevents.member.port.out.persistence -import site.yourevents.member.Member +import site.yourevents.member.domain.Member +import site.yourevents.member.domain.MemberVO interface MemberPersistencePort { fun findByEmail(email: String): Member? + + fun save(memberVO: MemberVO): Member } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt index 1b0e784..0d8507d 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt @@ -1,7 +1,9 @@ package site.yourevents.member.service import org.springframework.stereotype.Service -import site.yourevents.member.Member +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.member.domain.Member +import site.yourevents.member.domain.MemberVO import site.yourevents.member.port.`in`.MemberUseCase import site.yourevents.member.port.out.persistence.MemberPersistencePort @@ -12,4 +14,8 @@ class MemberService( override fun findByEmail(email: String): Member? { return memberPersistencePort.findByEmail(email) } -} \ No newline at end of file + + override fun createMember(kakaoProfile: KakaoProfile): Member { + return memberPersistencePort.save(MemberVO.from(kakaoProfile)) + } +} diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt index 6f38558..32e69ac 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt @@ -1,7 +1,9 @@ package site.yourevents.member.repository import org.springframework.stereotype.Repository -import site.yourevents.member.Member +import site.yourevents.member.domain.Member +import site.yourevents.member.domain.MemberVO +import site.yourevents.member.entity.MemberEntity import site.yourevents.member.port.out.persistence.MemberPersistencePort import kotlin.jvm.optionals.getOrNull @@ -13,4 +15,9 @@ class MemberRepository( return memberJPARepository.findByEmail(email) .getOrNull()?.toDomain() } + + override fun save(memberVO: MemberVO): Member { + return memberJPARepository.save(MemberEntity.from(memberVO)) + .toDomain() + } } From 6d2ff1ab9dd41a21fa156ed09ca3e07b1fc89e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 14:38:24 +0900 Subject: [PATCH 24/47] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=8C=8C=EC=82=AC=EB=93=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/auth/facade/AuthFacade.kt | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt index 4a5f983..d1e8ab5 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt @@ -1,14 +1,42 @@ package site.yourevents.auth.facade import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional import site.yourevents.auth.dto.request.LoginRequest import site.yourevents.auth.dto.response.LoginResponse +import site.yourevents.auth.port.`in`.usecase.AuthUseCase +import site.yourevents.auth.port.`in`.usecase.TokenUseCase +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.member.domain.Member +import site.yourevents.member.port.`in`.MemberUseCase @Service +@Transactional class AuthFacade( - + private val authUseCase: AuthUseCase, + private val memberUseCase: MemberUseCase, + private val tokenUseCase: TokenUseCase, ) { fun login(request: LoginRequest): LoginResponse { - return TODO("소셜 로그인 구현") + val kakaoProfile: KakaoProfile = + authUseCase.getKakaoUserInfoFromCode(request.code) + + return getTokenResponse(kakaoProfile) + } + + private fun getTokenResponse(kakaoProfile: KakaoProfile): LoginResponse { + var member: Member? = memberUseCase.findByEmail(kakaoProfile.email) + + if (member == null) { + member = memberUseCase.createMember(kakaoProfile) + } + + val accessToken: String = tokenUseCase.generateAccessToken( + member.getId(), + member.getEmail(), + "ROLE_USER" + ) + + return LoginResponse.of(member.getId(), member.getEmail(), accessToken) } -} \ No newline at end of file +} From 4fca6f9f6e41597ff865d9a5b8a78f19064a96d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 14:39:46 +0900 Subject: [PATCH 25/47] =?UTF-8?q?chore:=20=ED=99=98=EA=B2=BD=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 21 +++++++++++++++++++ .../src/main/resources/application-local.yml | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/module-presentation/src/main/resources/application-dev.yml b/module-presentation/src/main/resources/application-dev.yml index 4d951bb..b58a6cb 100644 --- a/module-presentation/src/main/resources/application-dev.yml +++ b/module-presentation/src/main/resources/application-dev.yml @@ -14,6 +14,27 @@ spring: format_sql: true use_sql_comments: true + security: + oauth2: + client: + provider: + kakao: + authorization-uri: https://kauth.kakao.com/oauth/authorize + token-uri: https://kauth.kakao.com/oauth/token + user-info-uri: https://kapi.kakao.com/v2/user/me + user-name-attribute: id + registration: + kakao: + client-name: kakao + client-id: ENC(hUMHbWie9KAHtBWcInSZruPtxz5F+RaJPwdN9i9b7GGB+g/aDjEUfqMyPWabTJaH) + redirect-uri: http://localhost:3000/oauth + authorization-grant-type: authorization_code + scope: + - email + +jwt: + secret_key: ENC(7lgXugZgh5UxA+EJTS0qxPYZUoeOsOTgqZoLXtn0UQI=) + app: server: url: ENC(uN3Diby1cLKgQIKPznbuLr/9mQrqzUFhTlzKRp4ZCSxovF26NNCo+A==) diff --git a/module-presentation/src/main/resources/application-local.yml b/module-presentation/src/main/resources/application-local.yml index 86f4e0f..ef7d6df 100644 --- a/module-presentation/src/main/resources/application-local.yml +++ b/module-presentation/src/main/resources/application-local.yml @@ -14,6 +14,27 @@ spring: format_sql: true use_sql_comments: true + security: + oauth2: + client: + provider: + kakao: + authorization-uri: https://kauth.kakao.com/oauth/authorize + token-uri: https://kauth.kakao.com/oauth/token + user-info-uri: https://kapi.kakao.com/v2/user/me + user-name-attribute: id + registration: + kakao: + client-name: kakao + client-id: ENC(hUMHbWie9KAHtBWcInSZruPtxz5F+RaJPwdN9i9b7GGB+g/aDjEUfqMyPWabTJaH) + redirect-uri: http://localhost:8080/oauth + authorization-grant-type: authorization_code + scope: + - email + +jwt: + secret_key: ENC(7lgXugZgh5UxA+EJTS0qxPYZUoeOsOTgqZoLXtn0UQI=) + app: server: url: http://localhost:8080 From c244c3f01ae6dff57e1a9f2512f7055a06fc4bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 17:05:37 +0900 Subject: [PATCH 26/47] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=B0=8F=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filter/CustomExceptionHandleFilter.kt | 44 +++++++++++++++++++ .../jwt/CustomAccessDeniedHandler.kt | 29 ++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt create mode 100644 module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt new file mode 100644 index 0000000..a64d7f7 --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt @@ -0,0 +1,44 @@ +package site.yourevents.filter + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.jetbrains.annotations.NotNull +import org.springframework.web.filter.OncePerRequestFilter +import site.yourevents.error.exception.ServiceException +import site.yourevents.response.ApiResponse +import site.yourevents.type.ErrorCode + +class CustomExceptionHandleFilter : OncePerRequestFilter() { + override fun doFilterInternal( + @NotNull request: HttpServletRequest, + @NotNull response: HttpServletResponse, + @NotNull filterChain: FilterChain + ) { + runCatching { + filterChain.doFilter(request, response) + }.onFailure { exception -> + when (exception) { + is ServiceException -> sendErrorResponse(response, exception.errorCode) + else -> { + exception.printStackTrace() + sendErrorResponse(response, ErrorCode.INTERNAL_SERVER_ERROR) + } + } + } + } + + private fun sendErrorResponse(response: HttpServletResponse, errorCode: ErrorCode) { + response.apply { + status = errorCode.httpStatus + characterEncoding = "UTF-8" + contentType = "application/json" + } + + val errorResponse = ApiResponse.error(errorCode) + val result = mapOf("result" to errorResponse) + + ObjectMapper().writeValue(response.writer, result) + } +} \ No newline at end of file diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt new file mode 100644 index 0000000..324664a --- /dev/null +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt @@ -0,0 +1,29 @@ +package site.yourevents.jwt + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.jetbrains.annotations.NotNull +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.web.access.AccessDeniedHandler +import org.springframework.stereotype.Component +import site.yourevents.response.ApiResponse +import site.yourevents.type.ErrorCode + +@Component +class CustomAccessDeniedHandler : AccessDeniedHandler { + override fun handle( + @NotNull request: HttpServletRequest, + @NotNull response: HttpServletResponse, + @NotNull accessDeniedException: AccessDeniedException + ) { + response.contentType = "application/json;charset=UTF-8" + response.status = HttpServletResponse.SC_FORBIDDEN + + val jsonResponse: String = ObjectMapper().writeValueAsString( + ApiResponse.error(ErrorCode.ROLE_FORBIDDEN) + ) + + response.writer.write(jsonResponse) + } +} \ No newline at end of file From 98624b0fba6ceaafa11bce3eea3f5a0c6528af60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 17:06:06 +0900 Subject: [PATCH 27/47] =?UTF-8?q?feat:=20Security=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EB=B0=80=20=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4=EB=A7=81=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../error/exception/ServiceException.kt | 2 +- .../kotlin/site/yourevents/type/ErrorCode.kt | 1 + .../kotlin/site/yourevents/SecurityConfig.kt | 42 +++++++++++++++++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt b/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt index 05710c5..058428e 100644 --- a/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt +++ b/module-independent/src/main/kotlin/site/yourevents/error/exception/ServiceException.kt @@ -3,6 +3,6 @@ package site.yourevents.error.exception import site.yourevents.type.ErrorCode open class ServiceException( - private val errorCode: ErrorCode + val errorCode: ErrorCode ) : RuntimeException() { } diff --git a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt index be1ef55..1882784 100644 --- a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt +++ b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt @@ -10,6 +10,7 @@ enum class ErrorCode( MALFORMED_TOKEN(401, "MALFORMED_TOKEN", "위/변조된 토큰입니다."), UNSUPPORTED_TOKEN(401, "UNSUPPORTED_TOKEN", "지원하지 않는 토큰입니다."), EMPTY_AUTHENTICATION(401, "EMPTY_AUTHENTICATION", "인증정보가 존재하지 않습니다."), + ROLE_FORBIDDEN(403, "ROLE_FORBIDDEN", "접근할 수 있는 권한이 아닙니다."), MEMBER_NOT_FOUND(404, "MEMBER_NOT_FOUND", "존재하지 않는 사용자입니다."), INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR", "서버 오류가 발생했습니다."), } \ No newline at end of file diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt index 8055316..b47f2a2 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt @@ -9,15 +9,25 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.invoke import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.web.cors.CorsConfiguration import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource +import site.yourevents.filter.CustomExceptionHandleFilter +import site.yourevents.filter.JwtAuthenticationEntryPoint +import site.yourevents.filter.JwtAuthorizationFilter +import site.yourevents.jwt.CustomAccessDeniedHandler +import site.yourevents.jwt.JwtProvider @Configuration @EnableWebSecurity class SecurityConfig( @Value("\${app.server.url}") - private val serverUrl: String + private val serverUrl: String, + + private val jwtProvider: JwtProvider, + private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint, + private val customAccessDeniedHandler: CustomAccessDeniedHandler, ) { @Bean fun SecurityFilterChain(http: HttpSecurity): SecurityFilterChain { @@ -28,16 +38,39 @@ class SecurityConfig( authorize("/health-check", permitAll) authorize(anyRequest, permitAll) } + } + + http { csrf { disable() } formLogin { disable() } httpBasic { disable() } sessionManagement { SessionCreationPolicy.STATELESS } - // TODO: OAuth 설정 - // TODO: JJWT 설정 + cors { corsConfigurationSource() } + } + + http { + exceptionHandling { + accessDeniedHandler = customAccessDeniedHandler + authenticationEntryPoint = jwtAuthenticationEntryPoint + } + } + + http { + oauth2Login { } + } + + http { + addFilterBefore( + filter = JwtAuthorizationFilter(jwtProvider) + ) + addFilterBefore( + filter = CustomExceptionHandleFilter() + ) } return http.build() } + @Bean fun webSecurityCustomizer(): (WebSecurity) -> Unit { return { web -> @@ -53,7 +86,8 @@ class SecurityConfig( "http://localhost:3000", "https://www.yourevents.site", "https://yourevents.site", - serverUrl) + serverUrl + ) configuration.allowedMethods = listOf("POST", "GET", "PATCH", "DELETE", "OPTIONS") configuration.allowedHeaders = listOf("*") From c9a90cee49015be5d33bc623c0bc102f1b916f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 17:38:32 +0900 Subject: [PATCH 28/47] =?UTF-8?q?fix:=20Security=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=ED=97=A4=EB=8D=94=20null=EC=97=AC?= =?UTF-8?q?=EB=B6=80,=20CORS=20=EC=84=A4=EC=A0=95,=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/SecurityConfig.kt | 30 ++++++++++--------- .../filter/JwtAuthorizationFilter.kt | 5 ++-- .../site/yourevents/service/SocialClient.kt | 2 +- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt index b47f2a2..e7ac5fb 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt @@ -11,7 +11,8 @@ import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.web.cors.CorsConfiguration -import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource +import org.springframework.web.cors.CorsConfigurationSource +import org.springframework.web.cors.UrlBasedCorsConfigurationSource import site.yourevents.filter.CustomExceptionHandleFilter import site.yourevents.filter.JwtAuthenticationEntryPoint import site.yourevents.filter.JwtAuthorizationFilter @@ -80,19 +81,20 @@ class SecurityConfig( } @Bean - fun corsConfigurationSource(): UrlBasedCorsConfigurationSource { - val configuration = CorsConfiguration() - configuration.allowedOrigins = listOf( - "http://localhost:3000", - "https://www.yourevents.site", - "https://yourevents.site", - serverUrl - ) - configuration.allowedMethods = listOf("POST", "GET", "PATCH", "DELETE", "OPTIONS") - configuration.allowedHeaders = listOf("*") + fun corsConfigurationSource(): CorsConfigurationSource { + val configuration = CorsConfiguration().apply { + allowedOrigins = listOf( + "http://localhost:3000", + "https://www.yourevents.site", + "https://yourevents.site", + serverUrl + ) + allowedMethods = listOf("POST", "GET", "PATCH", "DELETE", "OPTIONS") + allowedHeaders = listOf("*") + } - val source = UrlBasedCorsConfigurationSource() - source.registerCorsConfiguration("/**", configuration) - return source + return UrlBasedCorsConfigurationSource().apply { + registerCorsConfiguration("/**", configuration) + } } } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt index c1eae4e..de03a5e 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt @@ -34,9 +34,8 @@ class JwtAuthorizationFilter( } private fun extractToken(request: HttpServletRequest): String? { - val authorizationHeader: String = request.getHeader(HEADER_PREFIX) - - if (authorizationHeader.startsWith(TOKEN_PREFIX)) { + val authorizationHeader: String? = request.getHeader(HEADER_PREFIX) + if (authorizationHeader != null && authorizationHeader.startsWith(TOKEN_PREFIX)) { return authorizationHeader.substringAfter(TOKEN_PREFIX) } return null diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt index 7173fcd..c2be611 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt @@ -17,7 +17,7 @@ class SocialClient( @Value("\${spring.security.oauth2.client.registration.kakao.client-id}") private val clientId: String, - @Value("\${spring.security.oauth2.client.registration.kakao.client-redirect-uri}") + @Value("\${spring.security.oauth2.client.registration.kakao.redirect-uri}") private val redirectUri: String, @Value("\${spring.security.oauth2.client.registration.kakao.authorization-grant-type}") From 6f358094341bb81d343385f4078756ce52e8af23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 17:57:04 +0900 Subject: [PATCH 29/47] =?UTF-8?q?fix:=20=EB=A6=AC=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EB=A0=89=ED=8A=B8=20uri=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-presentation/src/main/resources/application-dev.yml | 2 +- module-presentation/src/main/resources/application-local.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module-presentation/src/main/resources/application-dev.yml b/module-presentation/src/main/resources/application-dev.yml index b58a6cb..eb9707d 100644 --- a/module-presentation/src/main/resources/application-dev.yml +++ b/module-presentation/src/main/resources/application-dev.yml @@ -27,7 +27,7 @@ spring: kakao: client-name: kakao client-id: ENC(hUMHbWie9KAHtBWcInSZruPtxz5F+RaJPwdN9i9b7GGB+g/aDjEUfqMyPWabTJaH) - redirect-uri: http://localhost:3000/oauth + redirect-uri: http://localhost:3000/login/oauth authorization-grant-type: authorization_code scope: - email diff --git a/module-presentation/src/main/resources/application-local.yml b/module-presentation/src/main/resources/application-local.yml index ef7d6df..eaf5f26 100644 --- a/module-presentation/src/main/resources/application-local.yml +++ b/module-presentation/src/main/resources/application-local.yml @@ -27,7 +27,7 @@ spring: kakao: client-name: kakao client-id: ENC(hUMHbWie9KAHtBWcInSZruPtxz5F+RaJPwdN9i9b7GGB+g/aDjEUfqMyPWabTJaH) - redirect-uri: http://localhost:8080/oauth + redirect-uri: http://localhost:8080/login/oauth authorization-grant-type: authorization_code scope: - email From 37deadddd3bb1ffcabcddbf5591d5c40354a4d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 19:28:07 +0900 Subject: [PATCH 30/47] =?UTF-8?q?fix:=20EOL=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt | 2 +- .../src/main/kotlin/site/yourevents/type/ErrorCode.kt | 2 +- .../site/yourevents/filter/CustomExceptionHandleFilter.kt | 2 +- .../site/yourevents/filter/JwtAuthenticationEntryPoint.kt | 2 +- .../kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt | 2 +- .../kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt | 2 +- .../src/main/kotlin/site/yourevents/jwt/JwtProvider.kt | 2 +- .../src/main/kotlin/site/yourevents/principal/AuthDetails.kt | 2 +- .../src/main/kotlin/site/yourevents/auth/api/AuthController.kt | 3 +-- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt index dbc2518..f02fa6a 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/AuthUseCase.kt @@ -4,4 +4,4 @@ import site.yourevents.auth.vo.KakaoProfile interface AuthUseCase { fun getKakaoUserInfoFromCode(code: String): KakaoProfile -} \ No newline at end of file +} diff --git a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt index 1882784..e701e71 100644 --- a/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt +++ b/module-independent/src/main/kotlin/site/yourevents/type/ErrorCode.kt @@ -13,4 +13,4 @@ enum class ErrorCode( ROLE_FORBIDDEN(403, "ROLE_FORBIDDEN", "접근할 수 있는 권한이 아닙니다."), MEMBER_NOT_FOUND(404, "MEMBER_NOT_FOUND", "존재하지 않는 사용자입니다."), INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR", "서버 오류가 발생했습니다."), -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt index a64d7f7..b01c41c 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/CustomExceptionHandleFilter.kt @@ -41,4 +41,4 @@ class CustomExceptionHandleFilter : OncePerRequestFilter() { ObjectMapper().writeValue(response.writer, result) } -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt index f18d628..87b2014 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthenticationEntryPoint.kt @@ -27,4 +27,4 @@ class JwtAuthenticationEntryPoint : AuthenticationEntryPoint { response.writer.write(jsonResponse) } -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt index de03a5e..9a1b78f 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt @@ -40,4 +40,4 @@ class JwtAuthorizationFilter( } return null } -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt index 324664a..2d69443 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/CustomAccessDeniedHandler.kt @@ -26,4 +26,4 @@ class CustomAccessDeniedHandler : AccessDeniedHandler { response.writer.write(jsonResponse) } -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt index 4d310d5..a721ee8 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -112,4 +112,4 @@ class JwtProvider( } .isFailure } -} \ No newline at end of file +} diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt index 98b0785..c50e093 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt @@ -22,4 +22,4 @@ class AuthDetails( override fun getUsername(): String? { return email } -} \ No newline at end of file +} diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt index d4411b8..6ce2c2e 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt @@ -16,5 +16,4 @@ class AuthController( override fun login(request: LoginRequest): ApiResponse { return ApiResponse.success(SuccessCode.LOGIN_SUCCESS, authFacade.login(request)) } - -} \ No newline at end of file +} From ff66156ea81992c33b401729cea403abe0f383e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 21:29:42 +0900 Subject: [PATCH 31/47] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20socialId=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/yourevents/auth/vo/KakaoProfile.kt | 10 ++++++++-- .../site/yourevents/member/domain/Member.kt | 3 +++ .../site/yourevents/member/domain/MemberVO.kt | 7 ++++++- .../site/yourevents/member/entity/MemberEntity.kt | 5 +++++ .../dto/response/KakaoProfileResponse.kt | 15 ++++++++++++--- .../site/yourevents/service/SocialClient.kt | 10 +++++++--- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt index 66d6393..32fa4b8 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/vo/KakaoProfile.kt @@ -1,13 +1,19 @@ package site.yourevents.auth.vo data class KakaoProfile( + val socialId: String, val nickname: String, val email: String, ) { companion object { fun of( + socialId: String, nickname: String, - email: String - ): KakaoProfile = KakaoProfile(nickname, email) + email: String, + ): KakaoProfile = KakaoProfile( + socialId, + nickname, + email, + ) } } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt b/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt index bcdb3ae..3a1599d 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/domain/Member.kt @@ -4,11 +4,14 @@ import java.util.UUID class Member( private val id: UUID, + private val socialId: String, private val nickname: String, private val email: String, ) { fun getId(): UUID = id + fun getSocialId(): String = socialId + fun getNickname(): String = nickname fun getEmail(): String = email diff --git a/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt b/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt index c1232bd..99b1b79 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/domain/MemberVO.kt @@ -3,11 +3,16 @@ package site.yourevents.member.domain import site.yourevents.auth.vo.KakaoProfile data class MemberVO( + val socialId: String, val nickname: String, val email: String, ) { companion object { fun from(kakaoProfile: KakaoProfile): MemberVO = - MemberVO(kakaoProfile.nickname, kakaoProfile.email) + MemberVO( + kakaoProfile.socialId, + kakaoProfile.nickname, + kakaoProfile.email, + ) } } diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt index 0f2418c..4884766 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt @@ -15,6 +15,9 @@ class MemberEntity( @GeneratedValue(strategy = GenerationType.UUID) private val id: UUID? = null, + @Column + private val socialId: String, + @Column private val nickname: String, @@ -24,6 +27,7 @@ class MemberEntity( fun toDomain(): Member { return Member( id = id!!, + socialId = socialId, nickname = nickname, email = email, ) @@ -32,6 +36,7 @@ class MemberEntity( companion object { fun from(memberVO: MemberVO): MemberEntity { return MemberEntity( + socialId = memberVO.socialId, nickname = memberVO.nickname, email = memberVO.email, ) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt index bf43684..1ea2c8d 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt @@ -4,6 +4,7 @@ import com.google.gson.JsonObject import com.google.gson.JsonParser data class KakaoProfileResponse( + val socialId: String, val nickname: String, val email: String, ) { @@ -11,12 +12,20 @@ data class KakaoProfileResponse( fun from(jsonResponseBody: String): KakaoProfileResponse { val jsonObject: JsonObject = JsonParser.parseString(jsonResponseBody).asJsonObject + val email: String = jsonObject.get("email").asString val kakaoAccount: JsonObject = jsonObject.get("kakao_account").asJsonObject - val nickname: String = kakaoAccount.get("name").asString - val email: String = kakaoAccount.get("email").asString + val socialId: String = kakaoAccount.get("id").asString - return KakaoProfileResponse(nickname, email) + val profile: JsonObject = kakaoAccount.get("profile").asJsonObject + val nickname: String = profile.get("name").asString + + + return KakaoProfileResponse( + socialId, + nickname, + email, + ) } } } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt index c2be611..d2d205f 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/SocialClient.kt @@ -68,10 +68,14 @@ class SocialClient( val profileRequest = HttpEntity(null, headers) val response: ResponseEntity = - restTemplate.postForEntity(userInfoUri, profileRequest, String::class.java) + restTemplate.postForEntity(userInfoUri, profileRequest, String::class.java) - val profileResponse = KakaoProfileResponse.from(response.body!!) + val profileResponse = KakaoProfileResponse.from(response.body!!) - return KakaoProfile.of(profileResponse.nickname, profileResponse.email) + return KakaoProfile.of( + profileResponse.socialId, + profileResponse.nickname, + profileResponse.email, + ) } } From b5a2f998e41c3626147962417062143a2bc95ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 21:30:36 +0900 Subject: [PATCH 32/47] =?UTF-8?q?feat:=20=EC=9D=B8=EC=A6=9D=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=ED=8C=90=EB=B3=84=20=EA=B8=B0=EC=A4=80=20email=20-?= =?UTF-8?q?>=20socialId=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/port/in/usecase/TokenUseCase.kt | 6 +++++- .../yourevents/auth/port/out/SecurityPort.kt | 6 +++++- .../yourevents/auth/service/TokenService.kt | 12 +++++++++-- .../member/port/in/MemberUseCase.kt | 2 +- .../out/persistence/MemberPersistencePort.kt | 2 +- .../member/service/MemberService.kt | 4 ++-- .../member/repository/MemberJPARepository.kt | 2 +- .../member/repository/MemberRepository.kt | 4 ++-- .../kotlin/site/yourevents/jwt/JwtProvider.kt | 21 +++++++++++++------ .../site/yourevents/principal/AuthDetails.kt | 4 ++-- .../yourevents/service/AuthDetailsService.kt | 10 ++++++--- .../site/yourevents/auth/facade/AuthFacade.kt | 12 +++++++---- 12 files changed, 59 insertions(+), 26 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt index 44ed674..5f6ff1a 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/in/usecase/TokenUseCase.kt @@ -3,5 +3,9 @@ package site.yourevents.auth.port.`in`.usecase import java.util.UUID interface TokenUseCase { - fun generateAccessToken(id: UUID, email: String, role: String) : String + fun generateAccessToken( + id: UUID, + socialId: String, + role: String, + ): String } diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt index 9dc0979..6c686ac 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/port/out/SecurityPort.kt @@ -3,5 +3,9 @@ package site.yourevents.auth.port.out import java.util.UUID interface SecurityPort { - fun generateAccessToken(id: UUID, email: String, role: String) : String + fun generateAccessToken( + id: UUID, + socialId: String, + role: String, + ): String } diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt index c0f5bf6..1c71cc5 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt @@ -9,7 +9,15 @@ import java.util.UUID class TokenService( private val securityPort: SecurityPort, ) : TokenUseCase { - override fun generateAccessToken(id: UUID, email: String, role: String): String { - return securityPort.generateAccessToken(id, email, role) + override fun generateAccessToken( + id: UUID, + socialId: String, + role: String, + ): String { + return securityPort.generateAccessToken( + id, + socialId, + role, + ) } } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt index ce7092d..e20ef79 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/in/MemberUseCase.kt @@ -4,7 +4,7 @@ import site.yourevents.auth.vo.KakaoProfile import site.yourevents.member.domain.Member interface MemberUseCase { - fun findByEmail(email: String): Member? + fun findBySocialId(socialId: String): Member? fun createMember(kakaoProfile: KakaoProfile): Member } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt index 8b54c08..f2c0f33 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/port/out/persistence/MemberPersistencePort.kt @@ -4,7 +4,7 @@ import site.yourevents.member.domain.Member import site.yourevents.member.domain.MemberVO interface MemberPersistencePort { - fun findByEmail(email: String): Member? + fun findBySocialId(socialId: String): Member? fun save(memberVO: MemberVO): Member } diff --git a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt index 0d8507d..dcad71a 100644 --- a/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/member/service/MemberService.kt @@ -11,8 +11,8 @@ import site.yourevents.member.port.out.persistence.MemberPersistencePort class MemberService( private val memberPersistencePort: MemberPersistencePort ) : MemberUseCase { - override fun findByEmail(email: String): Member? { - return memberPersistencePort.findByEmail(email) + override fun findBySocialId(socialId: String): Member? { + return memberPersistencePort.findBySocialId(socialId) } override fun createMember(kakaoProfile: KakaoProfile): Member { diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt index 417c9bf..b0fbe90 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberJPARepository.kt @@ -6,5 +6,5 @@ import java.util.Optional import java.util.UUID interface MemberJPARepository : JpaRepository { - fun findByEmail(email: String): Optional + fun findBySocialId(socialId: String): Optional } diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt index 32e69ac..aa4e672 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/repository/MemberRepository.kt @@ -11,8 +11,8 @@ import kotlin.jvm.optionals.getOrNull class MemberRepository( private val memberJPARepository: MemberJPARepository ) : MemberPersistencePort { - override fun findByEmail(email: String): Member? { - return memberJPARepository.findByEmail(email) + override fun findBySocialId(socialId: String): Member? { + return memberJPARepository.findBySocialId(socialId) .getOrNull()?.toDomain() } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt index a721ee8..9d92df4 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -42,21 +42,30 @@ class JwtProvider( return SecretKeySpec(keyBytes, "HmacSHA256") } - override fun generateAccessToken(memberId: UUID, email: String, role: String): String { - return generateToken(memberId, email, ACCESS_TOKEN_DURATION, role) + override fun generateAccessToken( + memberId: UUID, + socialId: String, + role: String, + ): String { + return generateToken( + memberId, + socialId, + ACCESS_TOKEN_DURATION, + role, + ) } private fun generateToken( memberId: UUID, - email: String, + socialId: String, duration: Duration, - role: String + role: String, ): String { val now = Date() val expiry = Date(now.time + duration.inWholeMilliseconds) return Jwts.builder() - .subject(email) + .subject(socialId) .claim("id", memberId) .claim("role", role) .expiration(expiry) @@ -64,7 +73,7 @@ class JwtProvider( .compact() } - fun getAuthentication(token: String) : Authentication { + fun getAuthentication(token: String): Authentication { val claims = validateToken(token) val authorities: Collection? = Collections.singletonList( SimpleGrantedAuthority(claims["role"].toString()) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt index c50e093..b5eb904 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt @@ -8,7 +8,7 @@ import java.util.UUID class AuthDetails( private val uuid: UUID, - private val email: String, + private val socialId: String, private val role: String, ) : UserDetails { override fun getAuthorities(): Collection? { @@ -20,6 +20,6 @@ class AuthDetails( } override fun getUsername(): String? { - return email + return socialId } } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt index b979c4b..365cf1e 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/service/AuthDetailsService.kt @@ -10,10 +10,14 @@ import site.yourevents.principal.AuthDetails class AuthDetailsService( private val memberUseCase: MemberUseCase ) : UserDetailsService { - override fun loadUserByUsername(email: String): AuthDetails { - val member = memberUseCase.findByEmail(email) + override fun loadUserByUsername(socialId: String): AuthDetails { + val member = memberUseCase.findBySocialId(socialId) ?: throw MemberNotFountException() - return AuthDetails(member.getId(), member.getNickname(), "ROLE_USER") + return AuthDetails( + member.getId(), + member.getSocialId(), + "ROLE_USER", + ) } } diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt index d1e8ab5..1ee1552 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt @@ -25,7 +25,7 @@ class AuthFacade( } private fun getTokenResponse(kakaoProfile: KakaoProfile): LoginResponse { - var member: Member? = memberUseCase.findByEmail(kakaoProfile.email) + var member: Member? = memberUseCase.findBySocialId(kakaoProfile.socialId) if (member == null) { member = memberUseCase.createMember(kakaoProfile) @@ -33,10 +33,14 @@ class AuthFacade( val accessToken: String = tokenUseCase.generateAccessToken( member.getId(), - member.getEmail(), - "ROLE_USER" + member.getSocialId(), + "ROLE_USER", ) - return LoginResponse.of(member.getId(), member.getEmail(), accessToken) + return LoginResponse.of( + member.getId(), + member.getSocialId(), + accessToken, + ) } } From 5bbc5a4613b4d55f6732aa2fe6e9217db75dcb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 21:35:12 +0900 Subject: [PATCH 33/47] =?UTF-8?q?fix:=20=ED=86=A0=ED=81=B0=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=ED=95=84=ED=84=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt | 2 +- .../src/main/kotlin/site/yourevents/jwt/JwtProvider.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt index 9a1b78f..d784f06 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/filter/JwtAuthorizationFilter.kt @@ -26,7 +26,7 @@ class JwtAuthorizationFilter( ) { val accessToken: String? = extractToken(request) - if (null != accessToken) { + if (accessToken != null && jwtProvider.isValidToken(accessToken)) { val authentication: Authentication = jwtProvider.getAuthentication(accessToken) SecurityContextHolder.getContext().authentication = authentication } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt index 9d92df4..bbb83f3 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -108,7 +108,7 @@ class JwtProvider( } } - fun isInvalidToken(token: String): Boolean { + fun isValidToken(token: String): Boolean { return runCatching { validateToken(token) } .onFailure { e -> if (e is InvalidTokenException || @@ -116,9 +116,9 @@ class JwtProvider( e is MalformedTokenException || e is UnsupportedTokenException ) { - return true + return false } } - .isFailure + .isSuccess } } From c2c2cc4f8116594584a6027a1e6a9b4559785d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 22:38:31 +0900 Subject: [PATCH 34/47] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20=EA=B0=92=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/site/yourevents/type/SuccessCode.kt | 2 +- .../yourevents/dto/response/KakaoProfileResponse.kt | 7 ++++--- .../main/kotlin/site/yourevents/jwt/JwtProvider.kt | 2 +- .../yourevents/auth/dto/response/LoginResponse.kt | 11 +++++++++-- .../kotlin/site/yourevents/auth/facade/AuthFacade.kt | 9 +++------ .../src/main/resources/application-dev.yml | 5 +++-- .../src/main/resources/application-local.yml | 3 ++- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt b/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt index bfa7774..e2b86e2 100644 --- a/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt +++ b/module-independent/src/main/kotlin/site/yourevents/type/SuccessCode.kt @@ -6,5 +6,5 @@ enum class SuccessCode( val message: String, ) { REQUEST_OK(200, "OK", "요청이 성공적으로 처리되었습니다."), - LOGIN_SUCCESS(201, "LOGIN_SUCCESS", "소셜 로그인이 정상적으로 처리되었습니다."), + LOGIN_SUCCESS(200, "LOGIN_SUCCESS", "소셜 로그인이 정상적으로 처리되었습니다."), } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt index 1ea2c8d..c0558e4 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt @@ -12,13 +12,14 @@ data class KakaoProfileResponse( fun from(jsonResponseBody: String): KakaoProfileResponse { val jsonObject: JsonObject = JsonParser.parseString(jsonResponseBody).asJsonObject - val email: String = jsonObject.get("email").asString + val socialId: String = jsonObject.get("id").asString val kakaoAccount: JsonObject = jsonObject.get("kakao_account").asJsonObject - val socialId: String = kakaoAccount.get("id").asString + + val email: String = kakaoAccount.get("email").asString val profile: JsonObject = kakaoAccount.get("profile").asJsonObject - val nickname: String = profile.get("name").asString + val nickname: String = profile.get("nickname").asString return KakaoProfileResponse( diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt index bbb83f3..78bd9cd 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/jwt/JwtProvider.kt @@ -38,7 +38,7 @@ class JwtProvider( private val secretKey: SecretKeySpec get() { - val keyBytes: ByteArray = Base64.getDecoder().decode(secret) + val keyBytes: ByteArray = Base64.getUrlDecoder().decode(secret) return SecretKeySpec(keyBytes, "HmacSHA256") } diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt index 13968c5..ee788d4 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/dto/response/LoginResponse.kt @@ -4,14 +4,21 @@ import java.util.UUID data class LoginResponse( val userId: UUID, + val socialId: String, val nickname: String, val accessToken: String, ) { companion object { fun of( userId: UUID, + socialId: String, nickname: String, - accessToken: String - ): LoginResponse = LoginResponse(userId, nickname, accessToken) + accessToken: String, + ): LoginResponse = LoginResponse( + userId, + socialId, + nickname, + accessToken, + ) } } diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt index 1ee1552..cce9883 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/facade/AuthFacade.kt @@ -7,7 +7,6 @@ import site.yourevents.auth.dto.response.LoginResponse import site.yourevents.auth.port.`in`.usecase.AuthUseCase import site.yourevents.auth.port.`in`.usecase.TokenUseCase import site.yourevents.auth.vo.KakaoProfile -import site.yourevents.member.domain.Member import site.yourevents.member.port.`in`.MemberUseCase @Service @@ -25,11 +24,8 @@ class AuthFacade( } private fun getTokenResponse(kakaoProfile: KakaoProfile): LoginResponse { - var member: Member? = memberUseCase.findBySocialId(kakaoProfile.socialId) - - if (member == null) { - member = memberUseCase.createMember(kakaoProfile) - } + val member = memberUseCase.findBySocialId(kakaoProfile.socialId) + ?: memberUseCase.createMember(kakaoProfile) val accessToken: String = tokenUseCase.generateAccessToken( member.getId(), @@ -40,6 +36,7 @@ class AuthFacade( return LoginResponse.of( member.getId(), member.getSocialId(), + member.getNickname(), accessToken, ) } diff --git a/module-presentation/src/main/resources/application-dev.yml b/module-presentation/src/main/resources/application-dev.yml index eb9707d..378ee1a 100644 --- a/module-presentation/src/main/resources/application-dev.yml +++ b/module-presentation/src/main/resources/application-dev.yml @@ -30,17 +30,18 @@ spring: redirect-uri: http://localhost:3000/login/oauth authorization-grant-type: authorization_code scope: + - profile - email jwt: - secret_key: ENC(7lgXugZgh5UxA+EJTS0qxPYZUoeOsOTgqZoLXtn0UQI=) + secret_key: ENC(mGMgmCyPl7Gw4ungaWJ5B8iHFNsJft59DjR9fNnDmLAk7QfobVjwYyfNXNw4YhWAyBNS8OFMFnSr4aaHSSMWyXPQgRLowW0W) app: server: url: ENC(uN3Diby1cLKgQIKPznbuLr/9mQrqzUFhTlzKRp4ZCSxovF26NNCo+A==) sentry: - dsn: ENC(UefOk3EHvOlzQ+99rApWCWoEMEbTlVbECMRxnRLgtNzuWJa0PmWL1pBtfGRpRK6qWsOSGlmWlJsP7PI7JVaLOnHG3CDLM2bChy61gXTkqYiTs2I1Axf8SW/rxMmcEkH7PLOqEY/TI5I= + dsn: ENC(UefOk3EHvOlzQ+99rApWCWoEMEbTlVbECMRxnRLgtNzuWJa0PmWL1pBtfGRpRK6qWsOSGlmWlJsP7PI7JVaLOnHG3CDLM2bChy61gXTkqYiTs2I1Axf8SW/rxMmcEkH7PLOqEY/TI5I=) environment: ENC(5Nbdf/7y1sF9NAU0jw0SCg==) servername: ENC(Tf/+6HqlCb8m17xkhfHjhw==) diff --git a/module-presentation/src/main/resources/application-local.yml b/module-presentation/src/main/resources/application-local.yml index eaf5f26..cd7bda3 100644 --- a/module-presentation/src/main/resources/application-local.yml +++ b/module-presentation/src/main/resources/application-local.yml @@ -30,10 +30,11 @@ spring: redirect-uri: http://localhost:8080/login/oauth authorization-grant-type: authorization_code scope: + - profile - email jwt: - secret_key: ENC(7lgXugZgh5UxA+EJTS0qxPYZUoeOsOTgqZoLXtn0UQI=) + secret_key: ENC(mGMgmCyPl7Gw4ungaWJ5B8iHFNsJft59DjR9fNnDmLAk7QfobVjwYyfNXNw4YhWAyBNS8OFMFnSr4aaHSSMWyXPQgRLowW0W) app: server: From 4998810551cc452081544d4784b8997e5f84f9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Tue, 7 Jan 2025 23:24:30 +0900 Subject: [PATCH 35/47] =?UTF-8?q?chore:=20=EC=9B=8C=ED=81=AC=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95=20=EC=BD=94=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- .../security/src/main/kotlin/site/yourevents/SecurityConfig.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 941a8ff..6c1cef0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI with Test Results on: pull_request: - branches-ignore: [ "main" ] + branches: [ "main" ] jobs: dev-build-TEST: diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt index e7ac5fb..caec573 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/SecurityConfig.kt @@ -71,7 +71,6 @@ class SecurityConfig( return http.build() } - @Bean fun webSecurityCustomizer(): (WebSecurity) -> Unit { return { web -> From 144069cc98551227bbdac39a17cc3a45ea015e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 14:38:23 +0900 Subject: [PATCH 36/47] =?UTF-8?q?feat:=20=EC=A0=84=EC=97=AD=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/GlobalExceptionHandler.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 module-presentation/src/main/kotlin/site/yourevents/common/GlobalExceptionHandler.kt diff --git a/module-presentation/src/main/kotlin/site/yourevents/common/GlobalExceptionHandler.kt b/module-presentation/src/main/kotlin/site/yourevents/common/GlobalExceptionHandler.kt new file mode 100644 index 0000000..2115024 --- /dev/null +++ b/module-presentation/src/main/kotlin/site/yourevents/common/GlobalExceptionHandler.kt @@ -0,0 +1,34 @@ +package site.yourevents.common + +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice +import site.yourevents.error.exception.ServiceException +import site.yourevents.response.ApiResponse +import site.yourevents.type.ErrorCode + +@RestControllerAdvice +class GlobalExceptionHandler { + @ExceptionHandler(ServiceException::class) + fun handleCustomException( + e: ServiceException + ): ResponseEntity> { + val errorCode: ErrorCode = e.errorCode + + return ResponseEntity( + ApiResponse.error(errorCode), HttpStatus.valueOf(errorCode.httpStatus) + ) + } + + @ExceptionHandler(Exception::class) + fun handleCustomException( + e: Exception + ): ResponseEntity> { + val errorCode = ErrorCode.INTERNAL_SERVER_ERROR + + return ResponseEntity( + ApiResponse.error(errorCode), HttpStatus.valueOf(errorCode.httpStatus) + ) + } +} From 73a46ee5ef9af1e14409275881fc86e5ae7f4f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 17:19:55 +0900 Subject: [PATCH 37/47] =?UTF-8?q?feat:=20Member=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/member/domain/MemberTest.kt | 32 ++++++ .../yourevents/member/domain/MemberVOTest.kt | 53 ++++++++++ .../member/service/MemberServiceTest.kt | 98 +++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 module-domain/src/test/kotlin/site/yourevents/member/domain/MemberTest.kt create mode 100644 module-domain/src/test/kotlin/site/yourevents/member/domain/MemberVOTest.kt create mode 100644 module-domain/src/test/kotlin/site/yourevents/member/service/MemberServiceTest.kt diff --git a/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberTest.kt b/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberTest.kt new file mode 100644 index 0000000..e992706 --- /dev/null +++ b/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberTest.kt @@ -0,0 +1,32 @@ +package site.yourevents.member.domain + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import java.util.UUID + +class MemberTest : DescribeSpec({ + describe("Member 도메인") { + context("Member가 생성될 때") { + it("get 메서드를 통해 올바른 필드 값을 반환해야 한다.") { + val id = UUID.randomUUID() + val socialId = "12345678" + val nickname = "yes" + val email = "yes@yes.com" + + val member = Member( + id = id, + socialId = socialId, + nickname = nickname, + email = email + ) + + member.apply { + getId() shouldBe id + getSocialId() shouldBe socialId + getNickname() shouldBe nickname + getEmail() shouldBe email + } + } + } + } +}) diff --git a/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberVOTest.kt b/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberVOTest.kt new file mode 100644 index 0000000..6ca1666 --- /dev/null +++ b/module-domain/src/test/kotlin/site/yourevents/member/domain/MemberVOTest.kt @@ -0,0 +1,53 @@ +package site.yourevents.member.domain + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import site.yourevents.auth.vo.KakaoProfile + +class MemberVOTest : DescribeSpec({ + lateinit var socialId: String + lateinit var nickname: String + lateinit var email: String + + beforeTest { + socialId = "12345678" + nickname = "yes" + email = "yes@yes.com" + } + + describe("MemberVO") { + context("기본 생성자를 사용할 때") { + it("주어진 필드 값이 올바르게 주입되어야 한다") { + val memberVO = MemberVO( + socialId = socialId, + nickname = nickname, + email = email, + ) + + memberVO.apply { + socialId shouldBe socialId + nickname shouldBe nickname + email shouldBe email + } + } + } + + context("KakaoProfile에서 MemberVO로 변환할 때") { + it("from() 메서드를 통해 올바른 MemberVO가 생성되어야 한다") { + val kakaoProfile = KakaoProfile( + socialId = socialId, + nickname = nickname, + email = email, + ) + + val memberVO = MemberVO.from(kakaoProfile) + + memberVO.apply { + socialId shouldBe kakaoProfile.socialId + nickname shouldBe kakaoProfile.nickname + email shouldBe kakaoProfile.email + } + } + } + } +}) diff --git a/module-domain/src/test/kotlin/site/yourevents/member/service/MemberServiceTest.kt b/module-domain/src/test/kotlin/site/yourevents/member/service/MemberServiceTest.kt new file mode 100644 index 0000000..442183d --- /dev/null +++ b/module-domain/src/test/kotlin/site/yourevents/member/service/MemberServiceTest.kt @@ -0,0 +1,98 @@ +package site.yourevents.member.service + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.member.domain.Member +import site.yourevents.member.port.out.persistence.MemberPersistencePort +import java.util.UUID + +class MemberServiceTest : DescribeSpec({ + lateinit var memberPersistencePort: MemberPersistencePort + lateinit var memberService: MemberService + lateinit var id: UUID + lateinit var socialId: String + lateinit var nickname: String + lateinit var email: String + + beforeTest { + id = UUID.randomUUID() + socialId = "12345678" + nickname = "yes" + email = "yes@yes.com" + } + + // Mockk을 통해 DB 의존성을 제거 + beforeAny { + memberPersistencePort = mockk() + memberService = MemberService(memberPersistencePort) + } + + describe("MemberService") { + context("createMember() 메서드를 통해서") { + it("MemberPersistencePort.save() 메서드가 정상적으로 호출되어, Member가 반환되어야 한다.") { + val kakaoProfile = KakaoProfile( + socialId = socialId, + nickname = nickname, + email = email, + ) + + val mockMember = Member( + id = id, + socialId = kakaoProfile.socialId, + nickname = kakaoProfile.nickname, + email = kakaoProfile.email + ) + + every { memberPersistencePort.save(any()) } returns mockMember + + val result = memberService.createMember(kakaoProfile) + result shouldBe mockMember + + verify(exactly = 1) { + memberPersistencePort.save(match { + it.socialId == kakaoProfile.socialId + }) + } + confirmVerified(memberPersistencePort) + } + } + + context("findBySocialId() 메서드를 통해서") { + it("socialId로 Member를 찾을 수 있으면, 해당 Member를 반환한다") { + val mockMember = Member( + id = id, + socialId = socialId, + nickname = nickname, + email = email + ) + + every { memberPersistencePort.findBySocialId(socialId) } returns mockMember + + val result = memberService.findBySocialId(socialId) + result shouldBe mockMember + + verify(exactly = 1) { + memberPersistencePort.findBySocialId(socialId) + } + confirmVerified(memberPersistencePort) + } + + it("해당 socialId로 Member를 찾을 수 없으면, null을 반환한다") { + every { memberPersistencePort.findBySocialId(socialId) } returns null + + val result = memberService.findBySocialId(socialId) + result shouldBe null + + verify(exactly = 1) { + memberPersistencePort.findBySocialId(socialId) + } + confirmVerified(memberPersistencePort) + } + } + } +}) From b7d7161d9342a6d16c95888a27607dd8b5a56492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 17:27:10 +0900 Subject: [PATCH 38/47] =?UTF-8?q?chore:=20ci=20=EC=9B=8C=ED=81=AC=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c1cef0..0e8fb88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,13 +1,13 @@ -name: CI with Test Results +name: 테스트 통과 여부 검사 on: pull_request: branches: [ "main" ] jobs: - dev-build-TEST: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04 + build: steps: - name: GitHub Checkout uses: actions/checkout@v4 @@ -24,6 +24,8 @@ jobs: - name: Gradle 테스트 run: ./gradlew --info test + show-test: + steps: - name: Test 결과 출력 uses: EnricoMi/publish-unit-test-result-action@v2 if: always() From 955cf8c8d9be396ec48350c7066c625f4d8f8d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 17:32:29 +0900 Subject: [PATCH 39/47] =?UTF-8?q?chore:=20ci=20=EC=9B=8C=ED=81=AC=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e8fb88..f0df467 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,8 @@ on: branches: [ "main" ] jobs: - runs-on: ubuntu-22.04 - build: + runs-on: ubuntu-22.04 steps: - name: GitHub Checkout uses: actions/checkout@v4 @@ -25,6 +24,7 @@ jobs: run: ./gradlew --info test show-test: + runs-on: ubuntu-22.04 steps: - name: Test 결과 출력 uses: EnricoMi/publish-unit-test-result-action@v2 From 392c374f358cc00613b73ef332716bf2d63536ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 17:45:50 +0900 Subject: [PATCH 40/47] =?UTF-8?q?chore:=20ci=20=EC=9B=8C=ED=81=AC=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0df467..e041c96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: [ "main" ] jobs: - build: + test-result: runs-on: ubuntu-22.04 steps: - name: GitHub Checkout @@ -23,9 +23,6 @@ jobs: - name: Gradle 테스트 run: ./gradlew --info test - show-test: - runs-on: ubuntu-22.04 - steps: - name: Test 결과 출력 uses: EnricoMi/publish-unit-test-result-action@v2 if: always() From bb71c8e65cc4878ad5eaae59b797912f8da2d6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Wed, 8 Jan 2025 18:28:30 +0900 Subject: [PATCH 41/47] =?UTF-8?q?Auth=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthServiceTest.kt | 55 +++++++++++++++++++ .../auth/service/TokenServiceTest.kt | 53 ++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 module-domain/src/test/kotlin/site/yourevents/auth/service/AuthServiceTest.kt create mode 100644 module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt diff --git a/module-domain/src/test/kotlin/site/yourevents/auth/service/AuthServiceTest.kt b/module-domain/src/test/kotlin/site/yourevents/auth/service/AuthServiceTest.kt new file mode 100644 index 0000000..8835566 --- /dev/null +++ b/module-domain/src/test/kotlin/site/yourevents/auth/service/AuthServiceTest.kt @@ -0,0 +1,55 @@ +package site.yourevents.auth.service + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import site.yourevents.auth.port.out.SocialPort +import site.yourevents.auth.vo.KakaoProfile +import java.util.UUID + +class AuthServiceTest : DescribeSpec({ + lateinit var socialPort: SocialPort + lateinit var authService: AuthService + lateinit var id: UUID + lateinit var socialId: String + lateinit var nickname: String + lateinit var email: String + lateinit var authorizationCode: String + + beforeTest { + socialPort = mockk() + authService = AuthService(socialPort) + + id = UUID.randomUUID() + socialId = "12345678" + nickname = "yes" + email = "yes@yes.com" + authorizationCode = "someKindOfAuthorizationCode" + } + + describe("AuthService") { + context("정상적인 카카오 인증 코드가 주어졌을 때") { + it("SocialPort를 통해 KakaoProfile 정보를 받아와야 한다.") { + val code = authorizationCode + val mockProfile = KakaoProfile( + socialId = socialId, + nickname = nickname, + email = email, + ) + + every { socialPort.getKakaoUserInfoFromCode(code) } returns mockProfile + + val result = authService.getKakaoUserInfoFromCode(code) + result shouldBe mockProfile + + verify(exactly = 1) { + socialPort.getKakaoUserInfoFromCode(code) + } + confirmVerified(socialPort) + } + } + } +}) diff --git a/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt b/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt new file mode 100644 index 0000000..598752b --- /dev/null +++ b/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt @@ -0,0 +1,53 @@ +package site.yourevents.auth.service + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.confirmVerified +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import site.yourevents.auth.port.out.SecurityPort +import java.util.UUID + +class TokenServiceTest : DescribeSpec({ + lateinit var securityPort: SecurityPort + lateinit var tokenService: TokenService + lateinit var id: UUID + lateinit var socialId: String + lateinit var role: String + lateinit var accessToken: String + + beforeTest { + securityPort = mockk() + tokenService = TokenService(securityPort) + + id = UUID.randomUUID() + socialId = "12345678" + role = "ROLE_USER" + accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + } + + describe("TokenService") { + context("올바른 인자가 주어졌을 때") { + it("SecurityPort를 통해 토큰을 String 형식으로 반환받아야 한다.") { + every { securityPort.generateAccessToken(id, socialId, role) } returns accessToken + + val result = tokenService.generateAccessToken( + id, + socialId, + role, + ) + result shouldBe accessToken + + verify(exactly = 1) { + securityPort.generateAccessToken( + match { it == id }, + match { it == socialId }, + match { it == role }, + ) + } + confirmVerified(securityPort) + } + } + } +}) From c4b91164fd6f79002fe39094d1323ced81defe36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Thu, 9 Jan 2025 17:29:09 +0900 Subject: [PATCH 42/47] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/auth/service/TokenService.kt | 12 ++++----- .../auth/service/TokenServiceTest.kt | 8 +++++- .../yourevents/member/entity/MemberEntity.kt | 26 ++++++++----------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt index 1c71cc5..0f7c8ce 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/service/TokenService.kt @@ -13,11 +13,9 @@ class TokenService( id: UUID, socialId: String, role: String, - ): String { - return securityPort.generateAccessToken( - id, - socialId, - role, - ) - } + ): String = securityPort.generateAccessToken( + id, + socialId, + role, + ) } diff --git a/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt b/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt index 598752b..8a67381 100644 --- a/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt +++ b/module-domain/src/test/kotlin/site/yourevents/auth/service/TokenServiceTest.kt @@ -30,7 +30,13 @@ class TokenServiceTest : DescribeSpec({ describe("TokenService") { context("올바른 인자가 주어졌을 때") { it("SecurityPort를 통해 토큰을 String 형식으로 반환받아야 한다.") { - every { securityPort.generateAccessToken(id, socialId, role) } returns accessToken + every { + securityPort.generateAccessToken( + id, + socialId, + role + ) + } returns accessToken val result = tokenService.generateAccessToken( id, diff --git a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt index 4884766..bcdbcdb 100644 --- a/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt +++ b/module-infrastructure/persistence-db/src/main/kotlin/site/yourevents/member/entity/MemberEntity.kt @@ -24,22 +24,18 @@ class MemberEntity( @Column private val email: String, ) { - fun toDomain(): Member { - return Member( - id = id!!, - socialId = socialId, - nickname = nickname, - email = email, - ) - } + fun toDomain(): Member = Member( + id = id!!, + socialId = socialId, + nickname = nickname, + email = email, + ) companion object { - fun from(memberVO: MemberVO): MemberEntity { - return MemberEntity( - socialId = memberVO.socialId, - nickname = memberVO.nickname, - email = memberVO.email, - ) - } + fun from(memberVO: MemberVO): MemberEntity = MemberEntity( + socialId = memberVO.socialId, + nickname = memberVO.nickname, + email = memberVO.email, + ) } } From 68c8b4fc090e2d82e27eedf7054cc3a0f1a69afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Thu, 9 Jan 2025 21:25:04 +0900 Subject: [PATCH 43/47] =?UTF-8?q?test:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20mockMVC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/auth/api/AuthControllerTest.kt | 47 +++++++++++++++++++ .../health/api/HealthControllerTest.kt | 20 ++++++++ 2 files changed, 67 insertions(+) create mode 100644 module-presentation/src/test/kotlin/site/yourevents/auth/api/AuthControllerTest.kt create mode 100644 module-presentation/src/test/kotlin/site/yourevents/health/api/HealthControllerTest.kt diff --git a/module-presentation/src/test/kotlin/site/yourevents/auth/api/AuthControllerTest.kt b/module-presentation/src/test/kotlin/site/yourevents/auth/api/AuthControllerTest.kt new file mode 100644 index 0000000..93810ff --- /dev/null +++ b/module-presentation/src/test/kotlin/site/yourevents/auth/api/AuthControllerTest.kt @@ -0,0 +1,47 @@ +import com.fasterxml.jackson.databind.ObjectMapper +import io.kotest.core.spec.style.DescribeSpec +import io.mockk.every +import io.mockk.mockk +import org.springframework.http.MediaType +import org.springframework.test.web.servlet.post +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import site.yourevents.auth.api.AuthController +import site.yourevents.auth.dto.request.LoginRequest +import site.yourevents.auth.dto.response.LoginResponse +import site.yourevents.auth.facade.AuthFacade +import site.yourevents.type.SuccessCode +import java.util.UUID + +class AuthControllerTest : DescribeSpec({ + val authFacade = mockk() + val authController = AuthController(authFacade) + val mockMvc = MockMvcBuilders.standaloneSetup(authController).build() + + describe("AuthController") { + context("로그인 API 호출 시") { + it("로그인에 성공하면 SuccessCode와 LoginResponse를 반환한다") { + val accessToken = "eyQqklsdfIUedkslslk-1NLQI" + val loginRequest = LoginRequest( + code = "thisIsSomeKindOfAuthorizationCode" + ) + val loginResponse = LoginResponse( + userId = UUID.randomUUID(), + socialId = "12345678", + nickname = "yes!", + accessToken = accessToken + ) + + every { authFacade.login(loginRequest) } returns loginResponse + + mockMvc.post("/login") { + contentType = MediaType.APPLICATION_JSON + content = ObjectMapper().writeValueAsString(loginRequest) + }.andExpect { + status { isOk() } + jsonPath("$.code") { value(SuccessCode.LOGIN_SUCCESS.code) } + jsonPath("$.result.accessToken") { value(accessToken) } + } + } + } + } +}) diff --git a/module-presentation/src/test/kotlin/site/yourevents/health/api/HealthControllerTest.kt b/module-presentation/src/test/kotlin/site/yourevents/health/api/HealthControllerTest.kt new file mode 100644 index 0000000..d3c123e --- /dev/null +++ b/module-presentation/src/test/kotlin/site/yourevents/health/api/HealthControllerTest.kt @@ -0,0 +1,20 @@ +import io.kotest.core.spec.style.DescribeSpec +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import site.yourevents.health.api.HealthController +import site.yourevents.type.SuccessCode + +class HealthControllerTest : DescribeSpec({ + val healthController = HealthController() + val mockMvc = MockMvcBuilders.standaloneSetup(healthController).build() + + describe("HealthController") { + it("healthCheck() 메서드를 호출하면 200 OK를 반환한다.") { + mockMvc.get("/health-check") { + }.andExpect { + status { isOk() } + jsonPath("$.code") { value(SuccessCode.REQUEST_OK.code) } + } + } + } +}) From cb4d4224ab21df4abdf4332752fa62a5ad5d1aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Thu, 9 Jan 2025 22:48:41 +0900 Subject: [PATCH 44/47] =?UTF-8?q?test:=20AuthFacade=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/auth/facade/AuthFacadeTest.kt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 module-presentation/src/test/kotlin/site/yourevents/auth/facade/AuthFacadeTest.kt diff --git a/module-presentation/src/test/kotlin/site/yourevents/auth/facade/AuthFacadeTest.kt b/module-presentation/src/test/kotlin/site/yourevents/auth/facade/AuthFacadeTest.kt new file mode 100644 index 0000000..c3de9b8 --- /dev/null +++ b/module-presentation/src/test/kotlin/site/yourevents/auth/facade/AuthFacadeTest.kt @@ -0,0 +1,64 @@ +package site.yourevents.auth.facade + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk +import site.yourevents.auth.dto.request.LoginRequest +import site.yourevents.auth.dto.response.LoginResponse +import site.yourevents.auth.port.`in`.usecase.AuthUseCase +import site.yourevents.auth.port.`in`.usecase.TokenUseCase +import site.yourevents.auth.vo.KakaoProfile +import site.yourevents.member.domain.Member +import site.yourevents.member.port.`in`.MemberUseCase +import java.util.UUID + +class AuthFacadeTest : DescribeSpec({ + val authUseCase: AuthUseCase = mockk() + val memberUseCase: MemberUseCase = mockk() + val tokenUseCase: TokenUseCase = mockk() + val authFacade = AuthFacade( + authUseCase, + memberUseCase, + tokenUseCase + ) + + describe("AuthFacade") { + val code = "thisIsSomeKindOfAuthorizationCode" + val id = UUID.randomUUID() + val socialId = "12345678" + val nickname = "yes!" + val email = "yes@yes.com" + val accessToken = "eyQqklsdfIUedkslslk-1NLQI" + + context("login() 메서드에서 유효한 KakaoProfile이 주어질 때") { + it("로그인을 성공하고 LoginResponse를 반환해야 한다") { + val request = LoginRequest(code) + val kakaoProfile = KakaoProfile( + socialId, + nickname, + email, + ) + val member = Member( + id, + socialId, + nickname, + email, + ) + val expectedResponse = LoginResponse( + id, + socialId, + nickname, + accessToken + ) + + every { authUseCase.getKakaoUserInfoFromCode(any()) } returns kakaoProfile + every { memberUseCase.findBySocialId(any()) } returns member + every { tokenUseCase.generateAccessToken(any(), any(), any()) } returns accessToken + + val response = authFacade.login(request) + response shouldBe expectedResponse + } + } + } +}) From 0ce9c62f55844a80c7269fd8614e09ddd1a06629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Fri, 10 Jan 2025 00:25:31 +0900 Subject: [PATCH 45/47] =?UTF-8?q?test:=20persistent-db=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence-db/build.gradle.kts | 3 + .../site/yourevents/TestConfiguration.kt | 7 +++ .../member/repository/MemberRepositoryTest.kt | 59 +++++++++++++++++++ .../resources/application-persistence-db.yml | 16 +++++ 4 files changed, 85 insertions(+) create mode 100644 module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/TestConfiguration.kt create mode 100644 module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/member/repository/MemberRepositoryTest.kt create mode 100644 module-infrastructure/persistence-db/src/test/resources/application-persistence-db.yml diff --git a/module-infrastructure/persistence-db/build.gradle.kts b/module-infrastructure/persistence-db/build.gradle.kts index b75b517..262afdd 100644 --- a/module-infrastructure/persistence-db/build.gradle.kts +++ b/module-infrastructure/persistence-db/build.gradle.kts @@ -23,4 +23,7 @@ dependencies { // MySQL runtimeOnly("com.mysql:mysql-connector-j") + + //H2 Database for Test + testImplementation("com.h2database:h2:2.3.232") } diff --git a/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/TestConfiguration.kt b/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/TestConfiguration.kt new file mode 100644 index 0000000..1a181eb --- /dev/null +++ b/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/TestConfiguration.kt @@ -0,0 +1,7 @@ +package site.yourevents + +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class TestConfiguration { +} diff --git a/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/member/repository/MemberRepositoryTest.kt b/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/member/repository/MemberRepositoryTest.kt new file mode 100644 index 0000000..51ea5c5 --- /dev/null +++ b/module-infrastructure/persistence-db/src/test/kotlin/site/yourevents/member/repository/MemberRepositoryTest.kt @@ -0,0 +1,59 @@ +package site.yourevents.member.repository + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.jdbc.EmbeddedDatabaseConnection +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.test.context.ActiveProfiles +import site.yourevents.member.domain.MemberVO +import site.yourevents.member.entity.MemberEntity + +@ActiveProfiles("test") +@DataJpaTest +@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2, replace = AutoConfigureTestDatabase.Replace.NONE) +class MemberRepositoryTest( + @Autowired private val memberJPARepository: MemberJPARepository +) : DescribeSpec({ + val memberRepository = MemberRepository(memberJPARepository) + val socialId = "12345678" + val nickname = "yes!" + val email = "yes@yes.com" + + beforeSpec { + memberJPARepository.save( + MemberEntity.from( + MemberVO( + socialId, + nickname, + email, + ) + ) + ) + } + + afterSpec { + memberJPARepository.deleteAllInBatch() + } + + describe("MemberRepository") { + context("findBySocialId()에서 socialId가 주어지면") { + it("존재할 경우 Member를 반환해야 한다") { + val member = memberRepository.findBySocialId(socialId) + + member!!.apply { + getSocialId() shouldBe socialId + getNickname() shouldBe nickname + getEmail() shouldBe email + } + } + + it("존재하지 않는 경우 null을 반환해야 한다") { + val member = memberRepository.findBySocialId("11111111") + + member shouldBe null + } + } + } +}) diff --git a/module-infrastructure/persistence-db/src/test/resources/application-persistence-db.yml b/module-infrastructure/persistence-db/src/test/resources/application-persistence-db.yml new file mode 100644 index 0000000..88412ea --- /dev/null +++ b/module-infrastructure/persistence-db/src/test/resources/application-persistence-db.yml @@ -0,0 +1,16 @@ +spring: + config: + activate: + on-profile: test + + datasource: + url: jdbc:h2:mem:db;MODE=MYSQL + driver-class-name: org.h2.Driver + username: sa + password: + + jpa: + database-platform: org.hibernate.dialect.H2Dialect + show-sql: true + hibernate: + ddl-auto: create From f93ad984b3b8a76e082df3f243029c98c64c7b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sat, 11 Jan 2025 23:09:45 +0900 Subject: [PATCH 46/47] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/site/yourevents/auth/service/AuthService.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt b/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt index 2c2d99a..79ca5d0 100644 --- a/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt +++ b/module-domain/src/main/kotlin/site/yourevents/auth/service/AuthService.kt @@ -1,13 +1,11 @@ package site.yourevents.auth.service import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional import site.yourevents.auth.port.`in`.usecase.AuthUseCase import site.yourevents.auth.port.out.SocialPort import site.yourevents.auth.vo.KakaoProfile @Service -@Transactional class AuthService( private val socialPort: SocialPort ) : AuthUseCase { From cee299c6797da8b997f1ac86be5266f0eb2d1620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EC=A0=95=EC=99=84?= Date: Sat, 11 Jan 2025 23:46:59 +0900 Subject: [PATCH 47/47] =?UTF-8?q?style:=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=8B=A8=EC=9D=BC=20=ED=91=9C=ED=98=84?= =?UTF-8?q?=EC=8B=9D,=20nullable=20=EC=97=AC=EB=B7=B0,=20=EC=9D=B8?= =?UTF-8?q?=EB=8D=B1=EC=8A=A4=20=EC=A0=91=EA=B7=BC=EC=9E=90=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yourevents/dto/response/KakaoAccessToken.kt | 10 ++++------ .../dto/response/KakaoProfileResponse.kt | 11 +++++------ .../site/yourevents/principal/AuthDetails.kt | 14 ++++---------- .../site/yourevents/auth/api/AuthController.kt | 5 ++--- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt index 749db10..5606581 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoAccessToken.kt @@ -6,11 +6,9 @@ data class KakaoAccessToken( val accessToken: String ) { companion object { - fun from(jsonResponseBody: String): KakaoAccessToken { - val response = JsonParser.parseString(jsonResponseBody).asJsonObject - val accessToken = response.get("access_token").asString - - return KakaoAccessToken(accessToken) - } + fun from(jsonResponseBody: String) = KakaoAccessToken( + JsonParser.parseString(jsonResponseBody) + .asJsonObject["access_token"].asString + ) } } diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt index c0558e4..cf211c0 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/dto/response/KakaoProfileResponse.kt @@ -12,15 +12,14 @@ data class KakaoProfileResponse( fun from(jsonResponseBody: String): KakaoProfileResponse { val jsonObject: JsonObject = JsonParser.parseString(jsonResponseBody).asJsonObject - val socialId: String = jsonObject.get("id").asString + val socialId: String = jsonObject["id"].asString - val kakaoAccount: JsonObject = jsonObject.get("kakao_account").asJsonObject + val kakaoAccount: JsonObject = jsonObject["kakao_account"].asJsonObject - val email: String = kakaoAccount.get("email").asString - - val profile: JsonObject = kakaoAccount.get("profile").asJsonObject - val nickname: String = profile.get("nickname").asString + val email: String = kakaoAccount["email"].asString + val profile: JsonObject = kakaoAccount["profile"].asJsonObject + val nickname: String = profile["nickname"].asString return KakaoProfileResponse( socialId, diff --git a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt index b5eb904..5ccf2c9 100644 --- a/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt +++ b/module-infrastructure/security/src/main/kotlin/site/yourevents/principal/AuthDetails.kt @@ -3,7 +3,6 @@ package site.yourevents.principal import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetails -import java.util.Collections import java.util.UUID class AuthDetails( @@ -11,15 +10,10 @@ class AuthDetails( private val socialId: String, private val role: String, ) : UserDetails { - override fun getAuthorities(): Collection? { - return Collections.singletonList(SimpleGrantedAuthority("ROLE_USER")) - } + override fun getAuthorities(): Collection = + listOf(SimpleGrantedAuthority("ROLE_USER")) - override fun getPassword(): String? { - return null - } + override fun getPassword(): String? = null - override fun getUsername(): String? { - return socialId - } + override fun getUsername(): String? = socialId } diff --git a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt index 6ce2c2e..00539de 100644 --- a/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt +++ b/module-presentation/src/main/kotlin/site/yourevents/auth/api/AuthController.kt @@ -13,7 +13,6 @@ class AuthController( private val authFacade: AuthFacade ) : AuthApi { @PostMapping("/login") - override fun login(request: LoginRequest): ApiResponse { - return ApiResponse.success(SuccessCode.LOGIN_SUCCESS, authFacade.login(request)) - } + override fun login(request: LoginRequest): ApiResponse = + ApiResponse.success(SuccessCode.LOGIN_SUCCESS, authFacade.login(request)) }