From eed72577ba7b3b5babd9e17b96428ca1473ed612 Mon Sep 17 00:00:00 2001 From: sejineer Date: Thu, 22 Aug 2024 01:39:55 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[REFACTOR]:=20domain=20module=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20exception=20=EB=8D=98=EC=A7=80=EA=B2=8C=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 --- .../core/domain/error/CoreErrorType.kt | 2 +- .../myongjiway/core/domain/token/TokenReader.kt | 4 +++- .../myongjiway/core/domain/token/TokenService.kt | 8 ++------ .../myongjiway/core/domain/user/UserReader.kt | 6 ++++-- .../myongjiway/core/domain/user/UserService.kt | 2 +- .../com/myongjiway/token/TokenReaderTest.kt | 4 ++-- .../com/myongjiway/token/TokenServiceTest.kt | 16 ++++++++-------- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/error/CoreErrorType.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/error/CoreErrorType.kt index 34eca1a..cb286e0 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/error/CoreErrorType.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/error/CoreErrorType.kt @@ -21,7 +21,7 @@ enum class CoreErrorType( * 토큰 관련 에러 */ UNAUTHORIZED_TOKEN(CoreErrorKind.SERVER_ERROR, CoreErrorCode.TOKEN0001, "토큰이 유효하지 않습니다. 로그인을 다시 해주세요.", CoreErrorLevel.INFO), - NOT_FOUND_TOKEN(CoreErrorKind.SERVER_ERROR, CoreErrorCode.TOKEN0002, "이미 로그아웃 된 유저입니다. 로그인을 다시 해주세요.", CoreErrorLevel.INFO), + TOKEN_NOT_FOUND(CoreErrorKind.SERVER_ERROR, CoreErrorCode.TOKEN0002, "이미 로그아웃 된 유저입니다. 로그인을 다시 해주세요.", CoreErrorLevel.INFO), /* * 공지사항 관련 에러 diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenReader.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenReader.kt index 78cbfe3..ab0c01e 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenReader.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenReader.kt @@ -1,10 +1,12 @@ package com.myongjiway.core.domain.token +import com.myongjiway.core.domain.error.CoreErrorType +import com.myongjiway.core.domain.error.CoreException import org.springframework.stereotype.Component @Component class TokenReader( private val tokenRepository: TokenRepository, ) { - fun findByToken(token: String): Token? = tokenRepository.find(token) + fun find(token: String): Token = tokenRepository.find(token) ?: throw CoreException(CoreErrorType.TOKEN_NOT_FOUND) } diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt index b603534..c90abee 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt @@ -1,6 +1,5 @@ package com.myongjiway.core.domain.token -import com.myongjiway.core.domain.error.CoreErrorType import com.myongjiway.core.domain.user.UserReader import org.springframework.stereotype.Service @@ -13,11 +12,9 @@ class TokenService( private val tokenProcessor: TokenProcessor, ) { fun refresh(refreshData: RefreshData): TokenResult { - var refreshToken = tokenReader.findByToken(refreshData.refreshToken) - ?: throw com.myongjiway.core.domain.error.CoreException(CoreErrorType.UNAUTHORIZED_TOKEN) + var refreshToken = tokenReader.find(refreshData.refreshToken) val user = userReader.find(refreshToken.userId.toLong()) - ?: throw com.myongjiway.core.domain.error.CoreException(CoreErrorType.USER_NOT_FOUND) if (isExpired(refreshToken)) { refreshToken = tokenGenerator.generateRefreshTokenByUserId(user.id.toString()) @@ -30,8 +27,7 @@ class TokenService( fun delete(refreshToken: String) { val findRefreshToken = ( - tokenReader.findByToken(refreshToken) - ?: throw com.myongjiway.core.domain.error.CoreException(CoreErrorType.NOT_FOUND_TOKEN) + tokenReader.find(refreshToken) ) tokenProcessor.deleteToken(findRefreshToken.token) diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserReader.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserReader.kt index 504f00c..553f475 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserReader.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserReader.kt @@ -1,11 +1,13 @@ package com.myongjiway.core.domain.user +import com.myongjiway.core.domain.error.CoreErrorType +import com.myongjiway.core.domain.error.CoreException import org.springframework.stereotype.Component @Component class UserReader( private val userRepository: UserRepository, ) { - fun find(id: Long): User? = userRepository.findUserById(id) - fun find(providerId: String): User? = userRepository.findUserByProviderId(providerId) + fun find(id: Long): User = userRepository.findUserById(id) ?: throw CoreException(CoreErrorType.USER_NOT_FOUND) + fun find(providerId: String): User = userRepository.findUserByProviderId(providerId) ?: throw CoreException(CoreErrorType.USER_NOT_FOUND) } diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserService.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserService.kt index b22a3d7..1fe8119 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserService.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/user/UserService.kt @@ -4,7 +4,7 @@ import org.springframework.stereotype.Service @Service class UserService( - private val userUpdater: com.myongjiway.core.domain.user.UserUpdater, + private val userUpdater: UserUpdater, ) { fun inactive(providerId: String): Long = userUpdater.inactive(providerId) } diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt index eb755df..cb0df36 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt @@ -32,7 +32,7 @@ class TokenReaderTest : ) // when - val refreshToken = sut.findByToken(token) + val refreshToken = sut.find(token) // then refreshToken?.token shouldBe token @@ -44,7 +44,7 @@ class TokenReaderTest : every { tokenRepository.find("token") } returns null // when - val refreshToken = sut.findByToken("token") + val refreshToken = sut.find("token") // then refreshToken shouldBe null diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt index f80f2cf..1430a03 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt @@ -59,7 +59,7 @@ class TokenServiceTest : scenario("RefreshToken의 expiration이 지나지 않았다면 AccessToken을 갱신한다.") { // given val expiration = System.currentTimeMillis() + 100000 - every { tokenReader.findByToken(any()) } returns Token( + every { tokenReader.find(any()) } returns Token( "1000", "refreshToken", expiration, @@ -90,7 +90,7 @@ class TokenServiceTest : // given val expiration = System.currentTimeMillis() - 100000 - every { tokenReader.findByToken(any()) } returns Token( + every { tokenReader.find(any()) } returns Token( "1000", "refreshToken", expiration, @@ -121,7 +121,7 @@ class TokenServiceTest : scenario("RefreshToken이 없다면 UNAUTHORIZED_TOKEN 에러를 반환한다.") { // given - every { tokenReader.findByToken(any()) } returns null + every { tokenReader.find(any()) } returns null // when val actual = runCatching { sut.refresh(RefreshData("refreshToken")) } @@ -133,7 +133,7 @@ class TokenServiceTest : scenario("User가 없다면 USER_NOT_FOUND 에러를 반환한다.") { // given val expiration = System.currentTimeMillis() - 10000 - every { tokenReader.findByToken(any()) } returns Token( + every { tokenReader.find(any()) } returns Token( "1000", "refreshToken", expiration, @@ -153,7 +153,7 @@ class TokenServiceTest : feature("토큰 삭제") { scenario("RefreshToken 삭제에 성공한다.") { // given - every { tokenReader.findByToken(any()) } returns Token( + every { tokenReader.find(any()) } returns Token( "1000", "refreshToken", 10000, @@ -165,19 +165,19 @@ class TokenServiceTest : sut.delete("refreshToken") // then - verify(exactly = 1) { tokenReader.findByToken("refreshToken") } + verify(exactly = 1) { tokenReader.find("refreshToken") } verify(exactly = 1) { tokenProcessor.deleteToken("refreshToken") } } scenario("RefreshToken이 존재하지 않는다면 NOT_FOUND_TOKEN 에러를 반환한다.") { // given - every { tokenReader.findByToken(any()) } returns null + every { tokenReader.find(any()) } returns null // when val actual = runCatching { sut.delete("refreshToken") } // then - actual.exceptionOrNull() shouldBe CoreException(CoreErrorType.NOT_FOUND_TOKEN) + actual.exceptionOrNull() shouldBe CoreException(CoreErrorType.TOKEN_NOT_FOUND) } } }, From f343a2dbb1b759af9a81845c207f6771e6a4d033 Mon Sep 17 00:00:00 2001 From: Park Sejin Date: Fri, 23 Aug 2024 01:25:09 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[FIX]:=20User,=20Token=20DB=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=82=AD=EC=A0=9C=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=80=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A7=8C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/api/auth/security/domain/JwtProvider.kt | 4 ++-- .../myongjiway/core/domain/token/TokenService.kt | 7 ++----- .../core/domain/token/TokenValidator.kt | 7 +++++-- .../com/myongjiway/token/TokenReaderTest.kt | 10 ++++++---- .../com/myongjiway/token/TokenServiceTest.kt | 8 ++++---- .../{UserFinderTest.kt => UserReaderTest.kt} | 16 ++++++++-------- .../storage/db/core/common/BaseEntity.kt | 1 + .../storage/db/core/user/UserCoreRepository.kt | 12 ++++++------ .../storage/db/core/user/UserJpaRepository.kt | 3 ++- .../db/core/user/UserCoreRepositoryTest.kt | 16 ++++++++-------- 10 files changed, 44 insertions(+), 40 deletions(-) rename core/core-domain/src/test/kotlin/com/myongjiway/user/{UserFinderTest.kt => UserReaderTest.kt} (86%) diff --git a/core/core-api/src/main/kotlin/com/myongjiway/core/api/auth/security/domain/JwtProvider.kt b/core/core-api/src/main/kotlin/com/myongjiway/core/api/auth/security/domain/JwtProvider.kt index d6f609c..d557def 100644 --- a/core/core-api/src/main/kotlin/com/myongjiway/core/api/auth/security/domain/JwtProvider.kt +++ b/core/core-api/src/main/kotlin/com/myongjiway/core/api/auth/security/domain/JwtProvider.kt @@ -19,7 +19,7 @@ class JwtProvider( ) { fun validateAccessTokenFromRequest(servletRequest: ServletRequest, token: String?): Boolean { try { - tokenValidator.validateWithSecretKey( + tokenValidator.validate( Keys.hmacShaKeyFor(jwtProperty.accessToken.secret.toByteArray()), token!!, ).subject.toLong() @@ -34,7 +34,7 @@ class JwtProvider( var user: User? = null try { val userId = - tokenValidator.validateWithSecretKey( + tokenValidator.validate( Keys.hmacShaKeyFor(jwtProperty.accessToken.secret.toByteArray()), token!!, ).subject.toLong() diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt index c90abee..e8b45ef 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt @@ -26,11 +26,8 @@ class TokenService( } fun delete(refreshToken: String) { - val findRefreshToken = ( - tokenReader.find(refreshToken) - ) - - tokenProcessor.deleteToken(findRefreshToken.token) + val foundRefreshToken = tokenReader.find(refreshToken) + tokenProcessor.deleteToken(foundRefreshToken.token) } private fun isExpired(refreshToken: Token?): Boolean = refreshToken?.expiration!! <= System.currentTimeMillis() diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt index e276761..1ba4fcc 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt @@ -8,12 +8,15 @@ import javax.crypto.SecretKey @Component class TokenValidator { - fun validateWithPublicKey(key: PublicKey, token: String): Claims = + fun validate(key: PublicKey, token: String): Claims = validateToken { Jwts.parser().verifyWith(key).build().parseSignedClaims(token).payload } - fun validateWithSecretKey(key: SecretKey, token: String): Claims = + fun validate(key: SecretKey, token: String): Claims = validateToken { Jwts.parser().verifyWith(key).build().parseSignedClaims(token).payload } + fun validate(token: String): Claims = + validateToken { Jwts.parser().build().parseSignedClaims(token).payload } + private inline fun validateToken(validation: () -> Claims): Claims = try { validation() } catch (e: Exception) { diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt index cb0df36..dbff3bd 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt @@ -1,5 +1,7 @@ package com.myongjiway.token +import com.myongjiway.core.domain.error.CoreErrorType +import com.myongjiway.core.domain.error.CoreException import com.myongjiway.core.domain.token.Token import com.myongjiway.core.domain.token.TokenReader import com.myongjiway.core.domain.token.TokenRepository @@ -39,15 +41,15 @@ class TokenReaderTest : refreshToken?.userId shouldBe "1000" } - scenario("토큰이 존재하지 않으면 null을 반환한다.") { + scenario("토큰이 존재하지 않으면 TOKEN_NOT_FOUND 에러를 반환한다.") { // given - every { tokenRepository.find("token") } returns null + every { tokenRepository.find("token") } throws CoreException(CoreErrorType.TOKEN_NOT_FOUND) // when - val refreshToken = sut.find("token") + val actual = kotlin.runCatching { sut.find("token") } // then - refreshToken shouldBe null + actual.exceptionOrNull() shouldBe CoreException(CoreErrorType.TOKEN_NOT_FOUND) } } }, diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt index 1430a03..3da06a1 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt @@ -121,13 +121,13 @@ class TokenServiceTest : scenario("RefreshToken이 없다면 UNAUTHORIZED_TOKEN 에러를 반환한다.") { // given - every { tokenReader.find(any()) } returns null + every { tokenReader.find(any()) } throws CoreException(CoreErrorType.TOKEN_NOT_FOUND) // when val actual = runCatching { sut.refresh(RefreshData("refreshToken")) } // then - actual.exceptionOrNull() shouldBe CoreException(CoreErrorType.UNAUTHORIZED_TOKEN) + actual.exceptionOrNull() shouldBe CoreException(CoreErrorType.TOKEN_NOT_FOUND) } scenario("User가 없다면 USER_NOT_FOUND 에러를 반환한다.") { @@ -140,7 +140,7 @@ class TokenServiceTest : TokenType.REFRESH, ) - every { userReader.find(1000) } returns null + every { userReader.find(1000) } throws CoreException(CoreErrorType.USER_NOT_FOUND) // when val actual = runCatching { sut.refresh(RefreshData("refreshToken")) } @@ -171,7 +171,7 @@ class TokenServiceTest : scenario("RefreshToken이 존재하지 않는다면 NOT_FOUND_TOKEN 에러를 반환한다.") { // given - every { tokenReader.find(any()) } returns null + every { tokenReader.find(any()) } throws CoreException(CoreErrorType.TOKEN_NOT_FOUND) // when val actual = runCatching { sut.delete("refreshToken") } diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserFinderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt similarity index 86% rename from core/core-domain/src/test/kotlin/com/myongjiway/user/UserFinderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt index ffca985..fb2409d 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserFinderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt @@ -1,5 +1,7 @@ package com.myongjiway.user +import com.myongjiway.core.domain.error.CoreErrorType +import com.myongjiway.core.domain.error.CoreException import com.myongjiway.core.domain.user.ProviderType import com.myongjiway.core.domain.user.Role import com.myongjiway.core.domain.user.User @@ -10,7 +12,7 @@ import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk -class UserFinderTest : +class UserReaderTest : FeatureSpec( { lateinit var sut: UserReader @@ -43,16 +45,15 @@ class UserFinderTest : // then actual shouldBe user } - scenario("유저 ID 조회시 유저가 없으면 null을 반환한다") { + scenario("유저 ID 조회시 유저가 없으면 USER_NOT_FOUND 에러를 반환한다") { // given every { userRepository.findUserById(1000L) } returns null // when - val actual = kotlin.runCatching { sut.find(1000) } - .exceptionOrNull() + val actual = kotlin.runCatching { sut.find(1000) }.exceptionOrNull() // then - actual shouldBe null + actual shouldBe CoreException(CoreErrorType.USER_NOT_FOUND) } scenario("유저 Provider ID로 유저를 조회한다") { // given @@ -69,11 +70,10 @@ class UserFinderTest : every { userRepository.findUserByProviderId("1234") } returns null // when - val actual = kotlin.runCatching { sut.find("1234") } - .exceptionOrNull() + val actual = kotlin.runCatching { sut.find("1234") }.exceptionOrNull() // then - actual shouldBe null + actual shouldBe CoreException(CoreErrorType.USER_NOT_FOUND) } } }, diff --git a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/common/BaseEntity.kt b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/common/BaseEntity.kt index 12ae1cb..834d5de 100644 --- a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/common/BaseEntity.kt +++ b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/common/BaseEntity.kt @@ -24,6 +24,7 @@ abstract class BaseEntity { var updatedAt: LocalDateTime? = null protected set + @Column var isDeleted: Boolean = false protected set } diff --git a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepository.kt b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepository.kt index 1ce8e70..cd0ed4e 100644 --- a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepository.kt +++ b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepository.kt @@ -12,12 +12,12 @@ class UserCoreRepository( private val userJpaRepository: UserJpaRepository, ) : UserRepository { override fun findUserById(id: Long): User? { - val user = userJpaRepository.findById(id).orElseThrow() - return user.toUser() + val user = userJpaRepository.findByIdAndIsDeleted(id, false) + return user?.toUser() } override fun findUserByProviderId(providerId: String): User? { - val user = userJpaRepository.findByProviderId(providerId) + val user = userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) return user?.toUser() } @@ -40,7 +40,7 @@ class UserCoreRepository( @Transactional override fun modify(providerId: String, profileImg: String, name: String, role: Role): Long { - val user = userJpaRepository.findByProviderId(providerId) + val user = userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) user?.update(profileImg, name, role) return user?.id!! @@ -54,7 +54,7 @@ class UserCoreRepository( providerType: ProviderType, role: Role, ): Long { - val user = userJpaRepository.findByProviderId(providerId) + val user = userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) ?: return append(providerId, profileImg, name, providerType, role) user.update(profileImg, name, role) @@ -63,7 +63,7 @@ class UserCoreRepository( @Transactional override fun inactive(providerId: String): Long { - val user = userJpaRepository.findByProviderId(providerId) + val user = userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) user?.inactive() return user?.id!! } diff --git a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserJpaRepository.kt b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserJpaRepository.kt index dfe592d..58adceb 100644 --- a/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserJpaRepository.kt +++ b/storage/db-core/src/main/kotlin/com/myongjiway/storage/db/core/user/UserJpaRepository.kt @@ -3,5 +3,6 @@ package com.myongjiway.storage.db.core.user import org.springframework.data.jpa.repository.JpaRepository interface UserJpaRepository : JpaRepository { - fun findByProviderId(providerId: String): UserEntity? + fun findByIdAndIsDeleted(id: Long, deleted: Boolean): UserEntity? + fun findByProviderIdAndIsDeleted(providerId: String, deleted: Boolean): UserEntity? } diff --git a/storage/db-core/src/test/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepositoryTest.kt b/storage/db-core/src/test/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepositoryTest.kt index d3bda75..7ea4887 100644 --- a/storage/db-core/src/test/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepositoryTest.kt +++ b/storage/db-core/src/test/kotlin/com/myongjiway/storage/db/core/user/UserCoreRepositoryTest.kt @@ -33,7 +33,7 @@ class UserCoreRepositoryTest : feature("유저 조회") { scenario("유저 ID로 유저를 조회한다") { // given - every { userJpaRepository.findById(1000L) } returns Optional.of(userEntity) + every { userJpaRepository.findByIdAndIsDeleted(1000L, false) } returns userEntity // when val actual = sut.findUserById(1000L) @@ -55,7 +55,7 @@ class UserCoreRepositoryTest : scenario("Provider ID로 유저를 조회한다.") { // given val providerId = "providerId" - every { userJpaRepository.findByProviderId(any()) } returns userEntity + every { userJpaRepository.findByProviderIdAndIsDeleted(any(), false) } returns userEntity // when val actual = sut.findUserByProviderId(providerId) @@ -66,7 +66,7 @@ class UserCoreRepositoryTest : scenario("Provider ID 조회시 유저가 없으면 null을 반환한다") { // given val providerId = "12345678" - every { userJpaRepository.findByProviderId(any()) } returns null + every { userJpaRepository.findByProviderIdAndIsDeleted(any(), false) } returns null // when val actual = sut.findUserByProviderId(providerId) @@ -101,7 +101,7 @@ class UserCoreRepositoryTest : val profileImg = "newImg.url" val name = "newTest" val role = Role.ADMIN - every { userJpaRepository.findByProviderId(providerId) } returns userEntity + every { userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) } returns userEntity // when val actual = sut.modify(providerId, profileImg, name, role) @@ -115,7 +115,7 @@ class UserCoreRepositoryTest : val profileImg = "newImg.url" val name = "newTest" val role = Role.ADMIN - every { userJpaRepository.findByProviderId(providerId) } returns null + every { userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) } returns null // when val actual = kotlin.runCatching { sut.modify(providerId, profileImg, name, role) } @@ -134,7 +134,7 @@ class UserCoreRepositoryTest : val name = "test" val providerType = ProviderType.KAKAO val role = Role.USER - every { userJpaRepository.findByProviderId(providerId) } returns null + every { userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) } returns null every { userJpaRepository.save(any()) } returns userEntity // when @@ -150,7 +150,7 @@ class UserCoreRepositoryTest : val name = "newTest" val providerType = ProviderType.KAKAO val role = Role.USER - every { userJpaRepository.findByProviderId(providerId) } returns userEntity + every { userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) } returns userEntity // when val actual = sut.upsert(providerId, profileImg, name, providerType, role) @@ -164,7 +164,7 @@ class UserCoreRepositoryTest : scenario("유저를 비활성화에 성공한다.") { // given val providerId = "123123123" - every { userJpaRepository.findByProviderId(providerId) } returns userEntity + every { userJpaRepository.findByProviderIdAndIsDeleted(providerId, false) } returns userEntity // when val actual = sut.inactive(providerId) From 238ceb64f6623d2e9bc69a5b53fc2c78981b8b44 Mon Sep 17 00:00:00 2001 From: Park Sejin Date: Fri, 23 Aug 2024 01:53:24 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[REFACTOR]:=20TokenValidator=EC=9D=98=20ref?= =?UTF-8?q?resh=20method=EB=A1=9C=20=ED=86=A0=ED=81=B0=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20+=20=EA=B0=B1=EC=8B=A0=EC=9D=84=20=EB=AC=B6?= =?UTF-8?q?=EC=96=B4=20TokenService=EC=9D=98=20refresh=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=80=EB=8F=85=EC=84=B1=20=EC=A6=9D=EB=8C=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/token/TokenGenerator.kt | 15 ++++++++ .../core/domain/token/TokenService.kt | 13 ++++--- .../core/domain/token/TokenValidator.kt | 3 -- .../myongjiway/token/TokenGeneratorTest.kt | 15 ++++++-- .../com/myongjiway/token/TokenServiceTest.kt | 35 +++++++++---------- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenGenerator.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenGenerator.kt index 1e815e7..32622da 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenGenerator.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenGenerator.kt @@ -1,5 +1,6 @@ package com.myongjiway.core.domain.token +import io.jsonwebtoken.ExpiredJwtException import io.jsonwebtoken.Jwts import io.jsonwebtoken.Jwts.SIG.HS512 import io.jsonwebtoken.security.Keys @@ -9,6 +10,8 @@ import java.util.Date @Component class TokenGenerator( private val jwtProperty: JwtProperty, + private val tokenValidator: TokenValidator, + private val tokenAppender: TokenAppender, ) { fun generateAccessTokenByUserId(userId: String): Token { val (expiration, secret) = getExpirationAndSecret(TokenType.ACCESS) @@ -37,6 +40,18 @@ class TokenGenerator( ) } + fun refresh(refreshToken: Token): Token { + val secret = getExpirationAndSecret(TokenType.REFRESH).second + try { + tokenValidator.validate(Keys.hmacShaKeyFor(secret.toByteArray()), refreshToken.token) + } catch (e: ExpiredJwtException) { + val newRefreshToken = generateRefreshTokenByUserId(refreshToken.userId) + tokenAppender.upsert(refreshToken.userId.toLong(), newRefreshToken.token, newRefreshToken.expiration) + return newRefreshToken + } + return refreshToken + } + private fun getExpirationAndSecret(tokenType: TokenType) = when (tokenType) { TokenType.ACCESS -> jwtProperty.accessToken.expiration to jwtProperty.accessToken.secret TokenType.REFRESH -> jwtProperty.refreshToken.expiration to jwtProperty.refreshToken.secret diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt index e8b45ef..f07c4e2 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenService.kt @@ -5,21 +5,22 @@ import org.springframework.stereotype.Service @Service class TokenService( - private val tokenAppender: TokenAppender, private val tokenGenerator: TokenGenerator, private val tokenReader: TokenReader, private val userReader: UserReader, private val tokenProcessor: TokenProcessor, ) { + /** + * RefreshToken을 이용하여 AccessToken을 재발급한다. RefreshToken 또한 만료되었다면 갱신한다. + * @param refreshData AccessToken을 재발급하기 위한 RefreshToken + * @return TokenResult 재발급된 AccessToken과 RefreshToken + */ fun refresh(refreshData: RefreshData): TokenResult { var refreshToken = tokenReader.find(refreshData.refreshToken) val user = userReader.find(refreshToken.userId.toLong()) - if (isExpired(refreshToken)) { - refreshToken = tokenGenerator.generateRefreshTokenByUserId(user.id.toString()) - tokenAppender.upsert(user.id, refreshToken.token, refreshToken.expiration) - } + refreshToken = tokenGenerator.refresh(refreshToken) val newAccessToken = tokenGenerator.generateAccessTokenByUserId(user.id.toString()) return TokenResult(newAccessToken.token, refreshToken.token) @@ -29,6 +30,4 @@ class TokenService( val foundRefreshToken = tokenReader.find(refreshToken) tokenProcessor.deleteToken(foundRefreshToken.token) } - - private fun isExpired(refreshToken: Token?): Boolean = refreshToken?.expiration!! <= System.currentTimeMillis() } diff --git a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt index 1ba4fcc..4ab8065 100644 --- a/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt +++ b/core/core-domain/src/main/kotlin/com/myongjiway/core/domain/token/TokenValidator.kt @@ -14,9 +14,6 @@ class TokenValidator { fun validate(key: SecretKey, token: String): Claims = validateToken { Jwts.parser().verifyWith(key).build().parseSignedClaims(token).payload } - fun validate(token: String): Claims = - validateToken { Jwts.parser().build().parseSignedClaims(token).payload } - private inline fun validateToken(validation: () -> Claims): Claims = try { validation() } catch (e: Exception) { diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt index d215a7b..50db1da 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt @@ -2,17 +2,22 @@ package com.myongjiway.token import com.myongjiway.core.domain.token.JwtProperty import com.myongjiway.core.domain.token.Token +import com.myongjiway.core.domain.token.TokenAppender import com.myongjiway.core.domain.token.TokenGenerator import com.myongjiway.core.domain.token.TokenType +import com.myongjiway.core.domain.token.TokenValidator import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf +import io.mockk.mockk import java.util.Date class TokenGeneratorTest : FeatureSpec( { lateinit var jwtProperty: JwtProperty + lateinit var tokenValidator: TokenValidator + lateinit var tokenAppender: TokenAppender lateinit var sut: TokenGenerator val userId = "1234" @@ -20,14 +25,18 @@ class TokenGeneratorTest : jwtProperty = JwtProperty().apply { accessToken = JwtProperty.TokenProperties().apply { expiration = 10000 - secret = "lnp1ISIafo9E+U+xZ4xr0kaRGD5uNVCT1tiJ8gXmqWvp32L7JoXC9EjAy0z2F6NVSwrKLxbCkpzT+DZJazy3Pg==" + secret = + "lnp1ISIafo9E+U+xZ4xr0kaRGD5uNVCT1tiJ8gXmqWvp32L7JoXC9EjAy0z2F6NVSwrKLxbCkpzT+DZJazy3Pg==" } refreshToken = JwtProperty.TokenProperties().apply { expiration = 1000000 - secret = "lnp1ISIafo9E+U+xZ4xr0kaRGD5uNVCT1tiJ8gXmqWvp32L7JoXC9EjAy0z2F6NVSwrKLxbCkpzT+DZJazy3Pg==" + secret = + "lnp1ISIafo9E+U+xZ4xr0kaRGD5uNVCT1tiJ8gXmqWvp32L7JoXC9EjAy0z2F6NVSwrKLxbCkpzT+DZJazy3Pg==" } } - sut = TokenGenerator(jwtProperty) + tokenAppender = mockk() + tokenValidator = mockk() + sut = TokenGenerator(jwtProperty, tokenValidator, tokenAppender) } feature("토큰 생성") { diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt index 3da06a1..ab6f6fa 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt @@ -4,7 +4,6 @@ import com.myongjiway.core.domain.error.CoreErrorType import com.myongjiway.core.domain.error.CoreException import com.myongjiway.core.domain.token.RefreshData import com.myongjiway.core.domain.token.Token -import com.myongjiway.core.domain.token.TokenAppender import com.myongjiway.core.domain.token.TokenGenerator import com.myongjiway.core.domain.token.TokenProcessor import com.myongjiway.core.domain.token.TokenReader @@ -24,7 +23,6 @@ class TokenServiceTest : FeatureSpec( { lateinit var tokenReader: TokenReader - lateinit var tokenAppender: TokenAppender lateinit var tokenGenerator: TokenGenerator lateinit var userReader: UserReader lateinit var tokenProcessor: TokenProcessor @@ -32,11 +30,10 @@ class TokenServiceTest : beforeTest { tokenReader = mockk() - tokenAppender = mockk() tokenGenerator = mockk() userReader = mockk() tokenProcessor = mockk() - sut = TokenService(tokenAppender, tokenGenerator, tokenReader, userReader, tokenProcessor) + sut = TokenService(tokenGenerator, tokenReader, userReader, tokenProcessor) every { tokenGenerator.generateAccessTokenByUserId(any()) } returns Token( "1000", @@ -44,15 +41,6 @@ class TokenServiceTest : 1000, TokenType.ACCESS, ) - - every { tokenGenerator.generateRefreshTokenByUserId(any()) } returns Token( - "1000", - "newRefreshToken", - 10000, - TokenType.REFRESH, - ) - - every { tokenAppender.upsert(any(), any(), any()) } returns 1 } feature("토큰 갱신") { @@ -77,18 +65,30 @@ class TokenServiceTest : mockk(), ) + every { tokenGenerator.refresh(any()) } returns Token( + "1000", + "refreshToken", + expiration, + TokenType.REFRESH, + ) + // when sut.refresh(RefreshData("refreshToken")) // then verify(exactly = 0) { tokenGenerator.generateRefreshTokenByUserId(any()) } verify(exactly = 1) { tokenGenerator.generateAccessTokenByUserId(any()) } - verify(exactly = 0) { tokenAppender.upsert(any(), any(), any()) } } scenario("RefreshToken의 expiration이 지났다면 RefreshToken과 AccessToken을 같이 갱신한다.") { // given val expiration = System.currentTimeMillis() - 100000 + every { tokenGenerator.refresh(any()) } returns Token( + "1000", + "newRefreshToken", + 10000, + TokenType.REFRESH, + ) every { tokenReader.find(any()) } returns Token( "1000", @@ -108,15 +108,12 @@ class TokenServiceTest : mockk(), ) - every { tokenAppender.upsert(any(), any(), any()) } returns 1 - // when - sut.refresh(RefreshData("refreshToken")) + val actual = sut.refresh(RefreshData("refreshToken")) // then - verify(exactly = 1) { tokenGenerator.generateRefreshTokenByUserId(any()) } verify(exactly = 1) { tokenGenerator.generateAccessTokenByUserId(any()) } - verify(exactly = 1) { tokenAppender.upsert(any(), any(), any()) } + actual.refreshToken shouldBe "newRefreshToken" } scenario("RefreshToken이 없다면 UNAUTHORIZED_TOKEN 에러를 반환한다.") { From e0a3b20f5fd41193e968f5a8d7b4505cdc5652ac Mon Sep 17 00:00:00 2001 From: Park Sejin Date: Fri, 23 Aug 2024 02:17:04 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[REFACTOR]:=20core-domain=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20test=20package=20=EA=B2=BD=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20TokenValidator=20test=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain}/CoreDomainContextTest.kt | 2 +- .../domain}/CoreDomainTestApplication.kt | 2 +- .../buslocation/BusLocationServiceTest.kt | 0 .../domain}/notice/NoticeCreatorTest.kt | 6 +- .../domain}/notice/NoticeDeleterTest.kt | 3 +- .../domain}/notice/NoticeFinderTest.kt | 7 +-- .../domain}/notice/NoticeUpdaterTest.kt | 7 +-- .../domain}/token/TokenAppenderTest.kt | 4 +- .../domain}/token/TokenGeneratorTest.kt | 8 +-- .../domain}/token/TokenProcessorTest.kt | 4 +- .../domain}/token/TokenReaderTest.kt | 6 +- .../domain}/token/TokenServiceTest.kt | 9 +-- .../core/domain/token/TokenValidatorTest.kt | 60 +++++++++++++++++++ .../domain}/user/UserAppenderTest.kt | 6 +- .../{ => core/domain}/user/UserReaderTest.kt | 7 +-- .../{ => core/domain}/user/UserServiceTest.kt | 4 +- .../{ => core/domain}/user/UserUpdaterTest.kt | 5 +- 17 files changed, 75 insertions(+), 65 deletions(-) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/CoreDomainContextTest.kt (91%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/CoreDomainTestApplication.kt (91%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/buslocation/BusLocationServiceTest.kt (100%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/notice/NoticeCreatorTest.kt (90%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/notice/NoticeDeleterTest.kt (98%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/notice/NoticeFinderTest.kt (96%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/notice/NoticeUpdaterTest.kt (93%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/token/TokenAppenderTest.kt (90%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/token/TokenGeneratorTest.kt (89%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/token/TokenProcessorTest.kt (85%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/token/TokenReaderTest.kt (88%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/token/TokenServiceTest.kt (94%) create mode 100644 core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenValidatorTest.kt rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/user/UserAppenderTest.kt (88%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/user/UserReaderTest.kt (90%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/user/UserServiceTest.kt (86%) rename core/core-domain/src/test/kotlin/com/myongjiway/{ => core/domain}/user/UserUpdaterTest.kt (90%) diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainContextTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainContextTest.kt similarity index 91% rename from core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainContextTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainContextTest.kt index 6e73d09..caa22b2 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainContextTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainContextTest.kt @@ -1,4 +1,4 @@ -package com.myongjiway +package com.myongjiway.core.domain import org.junit.jupiter.api.Tag import org.springframework.boot.test.context.SpringBootTest diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainTestApplication.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainTestApplication.kt similarity index 91% rename from core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainTestApplication.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainTestApplication.kt index 3930abd..664b95a 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/CoreDomainTestApplication.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/CoreDomainTestApplication.kt @@ -1,4 +1,4 @@ -package com.myongjiway +package com.myongjiway.core.domain import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/buslocation/BusLocationServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/buslocation/BusLocationServiceTest.kt similarity index 100% rename from core/core-domain/src/test/kotlin/com/myongjiway/buslocation/BusLocationServiceTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/buslocation/BusLocationServiceTest.kt diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeCreatorTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeCreatorTest.kt similarity index 90% rename from core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeCreatorTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeCreatorTest.kt index baf2393..5c3a5ad 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeCreatorTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeCreatorTest.kt @@ -1,9 +1,5 @@ -package com.myongjiway.notice +package com.myongjiway.core.domain.notice -import com.myongjiway.core.domain.notice.NoticeCreator -import com.myongjiway.core.domain.notice.NoticeMetadata -import com.myongjiway.core.domain.notice.NoticeRepository -import com.myongjiway.core.domain.notice.NoticeService import io.kotest.core.spec.style.FeatureSpec import io.mockk.Runs import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeDeleterTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeDeleterTest.kt similarity index 98% rename from core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeDeleterTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeDeleterTest.kt index c58093b..d1efd53 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeDeleterTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeDeleterTest.kt @@ -1,7 +1,6 @@ -package com.myongjiway.notice +package com.myongjiway.core.domain.notice import com.myongjiway.core.domain.error.CoreErrorType -import com.myongjiway.core.domain.notice.NoticeRepository import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeFinderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeFinderTest.kt similarity index 96% rename from core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeFinderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeFinderTest.kt index 0e2f219..d28c14c 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeFinderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeFinderTest.kt @@ -1,10 +1,5 @@ -package com.myongjiway.notice +package com.myongjiway.core.domain.notice -import com.myongjiway.core.domain.notice.NoticeFinder -import com.myongjiway.core.domain.notice.NoticeMetadata -import com.myongjiway.core.domain.notice.NoticeRepository -import com.myongjiway.core.domain.notice.NoticeService -import com.myongjiway.core.domain.notice.NoticeView import com.myongjiway.core.domain.usernotice.UserNotice import com.myongjiway.core.domain.usernotice.UserNoticeRepository import io.kotest.core.spec.style.FeatureSpec diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeUpdaterTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeUpdaterTest.kt similarity index 93% rename from core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeUpdaterTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeUpdaterTest.kt index 7a2c9ed..dcfc7db 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/notice/NoticeUpdaterTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/notice/NoticeUpdaterTest.kt @@ -1,10 +1,5 @@ -package com.myongjiway.notice +package com.myongjiway.core.domain.notice -import com.myongjiway.core.domain.notice.NoticeMetadata -import com.myongjiway.core.domain.notice.NoticeRepository -import com.myongjiway.core.domain.notice.NoticeService -import com.myongjiway.core.domain.notice.NoticeUpdater -import com.myongjiway.core.domain.notice.NoticeView import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenAppenderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenAppenderTest.kt similarity index 90% rename from core/core-domain/src/test/kotlin/com/myongjiway/token/TokenAppenderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenAppenderTest.kt index fdeacc5..03635b7 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenAppenderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenAppenderTest.kt @@ -1,7 +1,5 @@ -package com.myongjiway.token +package com.myongjiway.core.domain.token -import com.myongjiway.core.domain.token.TokenAppender -import com.myongjiway.core.domain.token.TokenRepository import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenGeneratorTest.kt similarity index 89% rename from core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenGeneratorTest.kt index 50db1da..2d6434f 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenGeneratorTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenGeneratorTest.kt @@ -1,11 +1,5 @@ -package com.myongjiway.token +package com.myongjiway.core.domain.token -import com.myongjiway.core.domain.token.JwtProperty -import com.myongjiway.core.domain.token.Token -import com.myongjiway.core.domain.token.TokenAppender -import com.myongjiway.core.domain.token.TokenGenerator -import com.myongjiway.core.domain.token.TokenType -import com.myongjiway.core.domain.token.TokenValidator import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenProcessorTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenProcessorTest.kt similarity index 85% rename from core/core-domain/src/test/kotlin/com/myongjiway/token/TokenProcessorTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenProcessorTest.kt index 07966fa..5afbb97 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenProcessorTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenProcessorTest.kt @@ -1,7 +1,5 @@ -package com.myongjiway.token +package com.myongjiway.core.domain.token -import com.myongjiway.core.domain.token.TokenProcessor -import com.myongjiway.core.domain.token.TokenRepository import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenReaderTest.kt similarity index 88% rename from core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenReaderTest.kt index dbff3bd..eba40c6 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenReaderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenReaderTest.kt @@ -1,11 +1,7 @@ -package com.myongjiway.token +package com.myongjiway.core.domain.token import com.myongjiway.core.domain.error.CoreErrorType import com.myongjiway.core.domain.error.CoreException -import com.myongjiway.core.domain.token.Token -import com.myongjiway.core.domain.token.TokenReader -import com.myongjiway.core.domain.token.TokenRepository -import com.myongjiway.core.domain.token.TokenType import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenServiceTest.kt similarity index 94% rename from core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenServiceTest.kt index ab6f6fa..74909e6 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/token/TokenServiceTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenServiceTest.kt @@ -1,14 +1,7 @@ -package com.myongjiway.token +package com.myongjiway.core.domain.token import com.myongjiway.core.domain.error.CoreErrorType import com.myongjiway.core.domain.error.CoreException -import com.myongjiway.core.domain.token.RefreshData -import com.myongjiway.core.domain.token.Token -import com.myongjiway.core.domain.token.TokenGenerator -import com.myongjiway.core.domain.token.TokenProcessor -import com.myongjiway.core.domain.token.TokenReader -import com.myongjiway.core.domain.token.TokenService -import com.myongjiway.core.domain.token.TokenType import com.myongjiway.core.domain.user.ProviderType import com.myongjiway.core.domain.user.Role import com.myongjiway.core.domain.user.User diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenValidatorTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenValidatorTest.kt new file mode 100644 index 0000000..1d4e5e1 --- /dev/null +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/token/TokenValidatorTest.kt @@ -0,0 +1,60 @@ +package com.myongjiway.core.domain.token + +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.Jwts.SIG.HS512 +import io.jsonwebtoken.security.Keys +import io.kotest.core.spec.style.FeatureSpec +import io.kotest.matchers.shouldNotBe +import java.util.Date + +class TokenValidatorTest : + FeatureSpec( + { + lateinit var sut: TokenValidator + + beforeTest { + sut = TokenValidator() + } + + feature("Public Key 토큰 유효성 검사") { + scenario("토큰이 유효하면 Claim을 반환한다.") { + // given + val secret = + "lnp1ISeIafo9E+UHxZ4xrXkaRGDaUuNVCT1tiJ8gXmq4vpseL7JoBC9EjAy0z296NVajinLxbCkopzT+DZJazy3Pg==" + val refreshToken = Jwts.builder() + .subject(1000L.toString()) + .expiration(Date(System.currentTimeMillis() + 100000)) + .signWith(Keys.hmacShaKeyFor(secret.toByteArray()), HS512) + .compact() + + // when + val actual = sut.validate(Keys.hmacShaKeyFor(secret.toByteArray()), refreshToken) + + // then + actual shouldNotBe null + } + + scenario("토큰이 유효하지 않으면 Exception을 반환한다.") { + // given + val secret = + "lnp1ISeIafo9E+UHxZ4xrXkaRGDaUuNVCT1tiJ8gXmq4vpseL7JoBC9EjAy0z296NVajinLxbCkopzT+DZJazy3Pg==" + val refreshToken = Jwts.builder() + .subject(1000L.toString()) + .expiration(Date(System.currentTimeMillis() + 100000)) + .signWith(Keys.hmacShaKeyFor((secret + "invalid").toByteArray()), HS512) + .compact() + + // when + val actual = kotlin.runCatching { + sut.validate( + Keys.hmacShaKeyFor(secret.toByteArray()), + refreshToken, + ) + }.exceptionOrNull() + + // then + actual shouldNotBe null + } + } + }, + ) diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserAppenderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserAppenderTest.kt similarity index 88% rename from core/core-domain/src/test/kotlin/com/myongjiway/user/UserAppenderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserAppenderTest.kt index c048756..ec974a4 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserAppenderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserAppenderTest.kt @@ -1,9 +1,5 @@ -package com.myongjiway.user +package com.myongjiway.core.domain.user -import com.myongjiway.core.domain.user.ProviderType -import com.myongjiway.core.domain.user.Role -import com.myongjiway.core.domain.user.UserAppender -import com.myongjiway.core.domain.user.UserRepository import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserReaderTest.kt similarity index 90% rename from core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserReaderTest.kt index fb2409d..0165e43 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserReaderTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserReaderTest.kt @@ -1,12 +1,7 @@ -package com.myongjiway.user +package com.myongjiway.core.domain.user import com.myongjiway.core.domain.error.CoreErrorType import com.myongjiway.core.domain.error.CoreException -import com.myongjiway.core.domain.user.ProviderType -import com.myongjiway.core.domain.user.Role -import com.myongjiway.core.domain.user.User -import com.myongjiway.core.domain.user.UserReader -import com.myongjiway.core.domain.user.UserRepository import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserServiceTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserServiceTest.kt similarity index 86% rename from core/core-domain/src/test/kotlin/com/myongjiway/user/UserServiceTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserServiceTest.kt index ba2a6ea..ddf4d5d 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserServiceTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserServiceTest.kt @@ -1,7 +1,5 @@ -package com.myongjiway.user +package com.myongjiway.core.domain.user -import com.myongjiway.core.domain.user.UserService -import com.myongjiway.core.domain.user.UserUpdater import io.kotest.core.spec.style.FeatureSpec import io.mockk.every import io.mockk.mockk diff --git a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserUpdaterTest.kt b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserUpdaterTest.kt similarity index 90% rename from core/core-domain/src/test/kotlin/com/myongjiway/user/UserUpdaterTest.kt rename to core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserUpdaterTest.kt index 4e8ae09..be8c4ac 100644 --- a/core/core-domain/src/test/kotlin/com/myongjiway/user/UserUpdaterTest.kt +++ b/core/core-domain/src/test/kotlin/com/myongjiway/core/domain/user/UserUpdaterTest.kt @@ -1,8 +1,5 @@ -package com.myongjiway.user +package com.myongjiway.core.domain.user -import com.myongjiway.core.domain.user.Role -import com.myongjiway.core.domain.user.UserRepository -import com.myongjiway.core.domain.user.UserUpdater import io.kotest.core.spec.style.FeatureSpec import io.kotest.matchers.shouldBe import io.mockk.every