From 5b3b3a767f8d96f6b5859128153db69704b5239d Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 28 Jul 2023 17:35:31 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B3=B8=EC=9D=B8=EC=9D=B8=EC=A6=9D=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 --- build.gradle.kts | 3 + .../co/vividnext/sodalive/member/auth/Auth.kt | 9 +-- .../sodalive/member/auth/AuthController.kt | 24 +++++++ .../sodalive/member/auth/AuthRepository.kt | 7 +++ .../sodalive/member/auth/AuthService.kt | 62 +++++++++++++++++++ .../sodalive/member/auth/AuthVerifyRequest.kt | 29 +++++++++ src/main/resources/application.yml | 4 ++ 7 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthVerifyRequest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 905258f..f55ad63 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -48,6 +48,9 @@ dependencies { implementation("com.amazonaws:aws-java-sdk-s3:1.12.380") implementation("com.amazonaws:aws-java-sdk-cloudfront:1.12.380") + // bootpay + implementation("io.github.bootpay:backend:2.2.1") + developmentOnly("org.springframework.boot:spring-boot-devtools") runtimeOnly("com.h2database:h2") runtimeOnly("com.mysql:mysql-connector-j") diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt index 570729b..1c66dfa 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt @@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.member.auth import kr.co.vividnext.sodalive.common.BaseEntity import kr.co.vividnext.sodalive.member.Member -import javax.persistence.CascadeType import javax.persistence.Column import javax.persistence.Entity import javax.persistence.FetchType @@ -18,10 +17,12 @@ data class Auth( @Column(columnDefinition = "TEXT", nullable = false) val uniqueCi: String, @Column(columnDefinition = "TEXT", nullable = false) - val di: String + val di: String, + @Column(nullable = false) + val gender: Int ) : BaseEntity() { - @OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL]) - @JoinColumn(name = "member_id", nullable = true) + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) var member: Member? = null set(value) { value?.auth = this diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt new file mode 100644 index 0000000..764a24e --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt @@ -0,0 +1,24 @@ +package kr.co.vividnext.sodalive.member.auth + +import kr.co.vividnext.sodalive.common.ApiResponse +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.Member +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/auth") +class AuthController(private val service: AuthService) { + @PostMapping + fun authVerify( + @RequestBody request: AuthVerifyRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.verify(member, request)) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthRepository.kt new file mode 100644 index 0000000..954dc91 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthRepository.kt @@ -0,0 +1,7 @@ +package kr.co.vividnext.sodalive.member.auth + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface AuthRepository : JpaRepository diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt new file mode 100644 index 0000000..76af74e --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt @@ -0,0 +1,62 @@ +package kr.co.vividnext.sodalive.member.auth + +import com.fasterxml.jackson.databind.ObjectMapper +import kr.co.bootpay.Bootpay +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.Member +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDate + +@Service +@Transactional(readOnly = true) +class AuthService( + private val repository: AuthRepository, + private val objectMapper: ObjectMapper, + + @Value("\${bootpay.application-id}") + private val bootpayApplicationId: String, + @Value("\${bootpay.private-key}") + private val bootpayPrivateKey: String +) { + @Transactional + fun verify(member: Member, request: AuthVerifyRequest) { + val bootpay = Bootpay(bootpayApplicationId, bootpayPrivateKey) + try { + val token = bootpay.accessToken + if (token["error_code"] != null) throw SodaException("인증정보에 오류가 있습니다.\n다시 시도해 주세요.") + + val res = bootpay.certificate(request.receiptId) + val certificateResult = objectMapper.convertValue(res, AuthCertificateResult::class.java) + + if ( + certificateResult.status == 12 && + certificateResult.statusLocale == "본인인증완료" && + certificateResult.receiptId == request.receiptId + ) { + val certificate = certificateResult.authenticateData + val nowYear = LocalDate.now().year + val certificateYear = certificate.birth.substring(0, 4).toInt() + if (nowYear - certificateYear >= 19) { + val auth = Auth( + name = certificate.name, + birth = certificate.birth, + uniqueCi = certificate.unique, + di = certificate.di, + gender = certificate.gender + ) + auth.member = member + + repository.save(auth) + } else { + throw SodaException("19세 미만 인증 오류") + } + } else { + throw SodaException("인증정보에 오류가 있습니다.\n다시 시도해 주세요.") + } + } catch (e: Exception) { + throw SodaException("인증정보에 오류가 있습니다.\n다시 시도해 주세요.") + } + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthVerifyRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthVerifyRequest.kt new file mode 100644 index 0000000..ea9590e --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthVerifyRequest.kt @@ -0,0 +1,29 @@ +package kr.co.vividnext.sodalive.member.auth + +import com.fasterxml.jackson.annotation.JsonProperty + +data class AuthVerifyRequest( + @JsonProperty("receipt_id") + val receiptId: String, + @JsonProperty("version") + val version: String? +) + +data class AuthVerifyCertificate( + val name: String, + val birth: String, + val unique: String, + val di: String, + val gender: Int +) + +data class AuthCertificateResult( + @JsonProperty("receipt_id") + val receiptId: String, + @JsonProperty("status") + val status: Int, + @JsonProperty("status_locale") + val statusLocale: String, + @JsonProperty("authenticate_data") + val authenticateData: AuthVerifyCertificate +) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9db65d5..180b5dd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,6 +8,10 @@ logging: util: EC2MetadataUtils: error +bootpay: + applicationId: ${BOOTPAY_APPLICATION_ID} + privateKey: ${BOOTPAY_PRIVATE_KEY} + cloud: aws: credentials: