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 index 764a24e..e0bc549 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthController.kt @@ -19,6 +19,15 @@ class AuthController(private val service: AuthService) { ) = run { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") - ApiResponse.ok(service.verify(member, request)) + val authenticateData = service.certificate(request, memberId = member.id!!) + + if (service.isBlockAuth(authenticateData)) { + service.signOut(member.id!!) + throw SodaException("운영정책을 위반하여 이용을 제한합니다.") + } else { + service.authenticate(authenticateData, member.id!!) + } + + ApiResponse.ok(null, null) } } 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 index a7a09f3..edfffe6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/AuthService.kt @@ -3,72 +3,94 @@ 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 kr.co.vividnext.sodalive.member.MemberRepository +import kr.co.vividnext.sodalive.member.MemberService +import kr.co.vividnext.sodalive.member.SignOut +import kr.co.vividnext.sodalive.member.SignOutRepository import org.springframework.beans.factory.annotation.Value +import org.springframework.data.repository.findByIdOrNull 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, + private val blockAuthRepository: BlockAuthRepository, + + private val memberService: MemberService, + private val memberRepository: MemberRepository, + private val signOutRepository: SignOutRepository, @Value("\${bootpay.application-id}") private val bootpayApplicationId: String, @Value("\${bootpay.private-key}") private val bootpayPrivateKey: String ) { - @Transactional - fun verify(member: Member, request: AuthVerifyRequest) { + fun certificate(request: AuthVerifyRequest, memberId: Long): AuthVerifyCertificate { val bootpay = Bootpay(bootpayApplicationId, bootpayPrivateKey) - val authId = repository.getAuthIdByMemberId(memberId = member.id!!) + val authId = repository.getAuthIdByMemberId(memberId = memberId) if (authId != null) throw SodaException("이미 인증된 계정입니다.") - try { + val certificateResult: AuthCertificateResult = 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 memberIds = repository.getActiveMemberIdsByDi(di = certificate.di) - if (memberIds.size >= 3) { - throw SodaException( - "이미 본인인증한 계정 ${memberIds.size}개 이용중입니다.\n" + - "소다라이브의 본인인증은 최대 3개의 계정만 이용할 수 있습니다." - ) - } - - 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다시 시도해 주세요.") - } + objectMapper.convertValue(res, AuthCertificateResult::class.java) } catch (e: Exception) { throw SodaException(e.message ?: "인증정보에 오류가 있습니다.\n다시 시도해 주세요.") } + + if ( + certificateResult.status == 12 && + certificateResult.statusLocale == "본인인증완료" && + certificateResult.receiptId == request.receiptId + ) { + return certificateResult.authenticateData + } else { + throw SodaException("인증정보에 오류가 있습니다.\n다시 시도해 주세요.") + } + } + + fun isBlockAuth(certificate: AuthVerifyCertificate): Boolean { + val blockAuthId = blockAuthRepository.findByUniqueCiAndDi(certificate.unique, certificate.di) + return blockAuthId != null && blockAuthId > 0 + } + + @Transactional + fun signOut(memberId: Long) { + val member = memberRepository.findByIdOrNull(memberId) ?: throw SodaException("로그인 정보를 확인해주세요.") + member.isActive = false + + val signOut = SignOut(reason = "운영정책을 위반하여 이용을 제한합니다.") + signOut.member = member + signOutRepository.save(signOut) + + memberService.logoutAll(memberId = memberId) + } + + @Transactional + fun authenticate(certificate: AuthVerifyCertificate, memberId: Long) { + val memberIds = repository.getActiveMemberIdsByDi(di = certificate.di) + if (memberIds.size >= 3) { + throw SodaException( + "이미 본인인증한 계정 ${memberIds.size}개 이용중입니다.\n" + + "소다라이브의 본인인증은 최대 3개의 계정만 이용할 수 있습니다." + ) + } + + val member = memberRepository.findByIdOrNull(memberId) ?: throw SodaException("로그인 정보를 확인해주세요.") + val auth = Auth( + name = certificate.name, + birth = certificate.birth, + uniqueCi = certificate.unique, + di = certificate.di, + gender = certificate.gender + ) + auth.member = member + + repository.save(auth) } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuth.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuth.kt new file mode 100644 index 0000000..4bd2d4a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuth.kt @@ -0,0 +1,19 @@ +package kr.co.vividnext.sodalive.member.auth + +import kr.co.vividnext.sodalive.common.BaseEntity +import javax.persistence.Column +import javax.persistence.Entity + +@Entity +data class BlockAuth( + @Column(nullable = false) + val name: String, + @Column(nullable = false) + val birth: String, + @Column(columnDefinition = "TEXT", nullable = false) + val uniqueCi: String, + @Column(columnDefinition = "TEXT", nullable = false) + val di: String, + @Column(nullable = false) + val gender: Int +) : BaseEntity() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuthRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuthRepository.kt new file mode 100644 index 0000000..ee36a52 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/auth/BlockAuthRepository.kt @@ -0,0 +1,27 @@ +package kr.co.vividnext.sodalive.member.auth + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.member.auth.QBlockAuth.blockAuth +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface BlockAuthRepository : JpaRepository, BlockAuthQueryRepository + +interface BlockAuthQueryRepository { + fun findByUniqueCiAndDi(uniqueCi: String, di: String): Long? +} + +@Repository +class BlockAuthQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : BlockAuthQueryRepository { + override fun findByUniqueCiAndDi(uniqueCi: String, di: String): Long? { + return queryFactory + .select(blockAuth.id) + .from(blockAuth) + .where( + blockAuth.uniqueCi.eq(uniqueCi) + .and(blockAuth.di.eq(di)) + ) + .fetchFirst() + } +}