| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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() | ||||
| @@ -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<BlockAuth, Long>, 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() | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user