generated from pricelees/issue-pr-template
[#30] 코드 구조 개선 #31
@ -3,64 +3,56 @@ package roomescape.auth.business
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.auth.exception.AuthException
|
||||
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||
import roomescape.auth.web.LoginCheckResponse
|
||||
import roomescape.auth.web.LoginRequest
|
||||
import roomescape.auth.web.LoginResponse
|
||||
import roomescape.common.exception.RoomescapeException
|
||||
import roomescape.member.business.MemberService
|
||||
import roomescape.member.implement.MemberFinder
|
||||
import roomescape.member.infrastructure.persistence.MemberEntity
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@Service
|
||||
class AuthService(
|
||||
private val memberService: MemberService,
|
||||
private val memberFinder: MemberFinder,
|
||||
private val jwtHandler: JwtHandler,
|
||||
) {
|
||||
@Transactional(readOnly = true)
|
||||
fun login(request: LoginRequest): LoginResponse {
|
||||
val params = "email=${request.email}, password=${request.password}"
|
||||
log.debug { "[AuthService.login] 로그인 시작: $params" }
|
||||
log.info { "[AuthService.login] 시작: $params" }
|
||||
|
||||
val member: MemberEntity = fetchMemberOrThrow(AuthErrorCode.LOGIN_FAILED, params, "login") {
|
||||
memberService.findByEmailAndPassword(request.email, request.password)
|
||||
val member: MemberEntity = fetchOrThrow(AuthErrorCode.LOGIN_FAILED) {
|
||||
memberFinder.findByEmailAndPassword(request.email, request.password)
|
||||
}
|
||||
|
||||
val accessToken: String = jwtHandler.createToken(member.id!!)
|
||||
|
||||
return LoginResponse(accessToken)
|
||||
.also { log.info { "[AuthService.login] 로그인 완료: memberId=${member.id}" } }
|
||||
.also { log.info { "[AuthService.login] 완료: email=${request.email}, memberId=${member.id}" } }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun checkLogin(memberId: Long): LoginCheckResponse {
|
||||
log.debug { "[AuthService.checkLogin] 로그인 확인 시작: memberId=$memberId" }
|
||||
val member: MemberEntity =
|
||||
fetchMemberOrThrow(AuthErrorCode.MEMBER_NOT_FOUND, "memberId=$memberId", "checkLogin") {
|
||||
memberService.findById(memberId)
|
||||
}
|
||||
log.info { "[AuthService.checkLogin] 시작: memberId=$memberId" }
|
||||
|
||||
val member: MemberEntity = fetchOrThrow(AuthErrorCode.MEMBER_NOT_FOUND) { memberFinder.findById(memberId) }
|
||||
|
||||
return LoginCheckResponse(member.name, member.role.name)
|
||||
.also { log.info { "[AuthService.checkLogin] 로그인 확인 완료: memberId=$memberId" } }
|
||||
.also { log.info { "[AuthService.checkLogin] 완료: memberId=$memberId, role=${it.role}" } }
|
||||
}
|
||||
|
||||
private fun fetchOrThrow(errorCode: AuthErrorCode, block: () -> MemberEntity): MemberEntity {
|
||||
try {
|
||||
return block()
|
||||
} catch (e: Exception) {
|
||||
throw AuthException(errorCode, e.message ?: errorCode.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun logout(memberId: Long) {
|
||||
log.info { "[AuthService.logout] 로그아웃: memberId=$memberId" }
|
||||
}
|
||||
|
||||
private fun fetchMemberOrThrow(
|
||||
errorCode: AuthErrorCode,
|
||||
params: String,
|
||||
calledBy: String,
|
||||
block: () -> MemberEntity,
|
||||
): MemberEntity {
|
||||
try {
|
||||
return block()
|
||||
} catch (e: Exception) {
|
||||
if (e !is RoomescapeException) {
|
||||
log.warn(e) { "[AuthService.$calledBy] 회원 조회 실패: $params" }
|
||||
}
|
||||
throw AuthException(errorCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,8 @@ import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import roomescape.auth.docs.AuthAPI
|
||||
import roomescape.auth.business.AuthService
|
||||
import roomescape.auth.docs.AuthAPI
|
||||
import roomescape.auth.web.support.MemberId
|
||||
import roomescape.common.dto.response.CommonApiResponse
|
||||
|
||||
|
||||
@ -11,14 +11,14 @@ import org.springframework.web.servlet.HandlerInterceptor
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.auth.exception.AuthException
|
||||
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||
import roomescape.member.business.MemberService
|
||||
import roomescape.member.implement.MemberFinder
|
||||
import roomescape.member.infrastructure.persistence.MemberEntity
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@Component
|
||||
class AuthInterceptor(
|
||||
private val memberService: MemberService,
|
||||
private val memberFinder: MemberFinder,
|
||||
private val jwtHandler: JwtHandler
|
||||
) : HandlerInterceptor {
|
||||
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
|
||||
@ -50,10 +50,10 @@ class AuthInterceptor(
|
||||
private fun findMember(accessToken: String?): MemberEntity {
|
||||
try {
|
||||
val memberId = jwtHandler.getMemberIdFromToken(accessToken)
|
||||
return memberService.findById(memberId)
|
||||
return memberFinder.findById(memberId)
|
||||
.also { MDC.put("member_id", "$memberId") }
|
||||
} catch (e: Exception) {
|
||||
log.info { "[AuthInterceptor] 회원 조회 실패. accessToken = ${accessToken}" }
|
||||
log.info { "[AuthInterceptor] 회원 조회 실패. accessToken = $accessToken" }
|
||||
val errorCode = AuthErrorCode.MEMBER_NOT_FOUND
|
||||
throw AuthException(errorCode, e.message ?: errorCode.message)
|
||||
}
|
||||
|
||||
@ -6,23 +6,21 @@ import io.kotest.core.spec.style.BehaviorSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.auth.exception.AuthException
|
||||
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||
import roomescape.member.business.MemberService
|
||||
import roomescape.member.exception.MemberErrorCode
|
||||
import roomescape.member.exception.MemberException
|
||||
import roomescape.member.implement.MemberFinder
|
||||
import roomescape.member.infrastructure.persistence.MemberEntity
|
||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||
import roomescape.util.JwtFixture
|
||||
import roomescape.util.MemberFixture
|
||||
import roomescape.util.TsidFactory
|
||||
|
||||
class AuthServiceTest : BehaviorSpec({
|
||||
val memberRepository: MemberRepository = mockk()
|
||||
val memberService = MemberService(TsidFactory, memberRepository)
|
||||
val memberFinder: MemberFinder = mockk()
|
||||
val jwtHandler: JwtHandler = JwtFixture.create()
|
||||
|
||||
val authService = AuthService(memberService, jwtHandler)
|
||||
val authService = AuthService(memberFinder, jwtHandler)
|
||||
val user: MemberEntity = MemberFixture.user()
|
||||
|
||||
Given("로그인 요청을 받으면") {
|
||||
@ -31,7 +29,7 @@ class AuthServiceTest : BehaviorSpec({
|
||||
|
||||
Then("회원이 있다면 JWT 토큰을 생성한 뒤 반환한다.") {
|
||||
every {
|
||||
memberRepository.findByEmailAndPassword(request.email, request.password)
|
||||
memberFinder.findByEmailAndPassword(request.email, request.password)
|
||||
} returns user
|
||||
|
||||
val accessToken: String = authService.login(request).accessToken
|
||||
@ -42,8 +40,8 @@ class AuthServiceTest : BehaviorSpec({
|
||||
|
||||
Then("회원이 없다면 예외를 던진다.") {
|
||||
every {
|
||||
memberRepository.findByEmailAndPassword(request.email, request.password)
|
||||
} returns null
|
||||
memberFinder.findByEmailAndPassword(request.email, request.password)
|
||||
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
|
||||
|
||||
val exception = shouldThrow<AuthException> {
|
||||
authService.login(request)
|
||||
@ -59,7 +57,7 @@ class AuthServiceTest : BehaviorSpec({
|
||||
val userId: Long = user.id!!
|
||||
|
||||
Then("회원이 있다면 회원의 이름을 반환한다.") {
|
||||
every { memberRepository.findByIdOrNull(userId) } returns user
|
||||
every { memberFinder.findById(userId) } returns user
|
||||
|
||||
val response = authService.checkLogin(userId)
|
||||
|
||||
@ -69,7 +67,9 @@ class AuthServiceTest : BehaviorSpec({
|
||||
}
|
||||
|
||||
Then("회원이 없다면 예외를 던진다.") {
|
||||
every { memberRepository.findByIdOrNull(userId) } returns null
|
||||
every {
|
||||
memberFinder.findById(userId)
|
||||
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
|
||||
|
||||
val exception = shouldThrow<AuthException> {
|
||||
authService.checkLogin(userId)
|
||||
|
||||
@ -4,12 +4,13 @@ import com.ninjasquad.springmockk.SpykBean
|
||||
import io.mockk.every
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import roomescape.auth.business.AuthService
|
||||
import roomescape.auth.exception.AuthErrorCode
|
||||
import roomescape.common.exception.CommonErrorCode
|
||||
import roomescape.common.exception.ErrorCode
|
||||
import roomescape.member.exception.MemberErrorCode
|
||||
import roomescape.member.exception.MemberException
|
||||
import roomescape.util.MemberFixture
|
||||
import roomescape.util.RoomescapeApiTest
|
||||
|
||||
@ -31,7 +32,7 @@ class AuthControllerTest(
|
||||
val expectedToken = "expectedToken"
|
||||
|
||||
every {
|
||||
memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
|
||||
memberFinder.findByEmailAndPassword(userRequest.email, userRequest.password)
|
||||
} returns user
|
||||
|
||||
every {
|
||||
@ -52,8 +53,8 @@ class AuthControllerTest(
|
||||
|
||||
When("회원을 찾지 못하면") {
|
||||
every {
|
||||
memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
|
||||
} returns null
|
||||
memberFinder.findByEmailAndPassword(userRequest.email, userRequest.password)
|
||||
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
|
||||
|
||||
Then("에러 응답을 받는다.") {
|
||||
val expectedError = AuthErrorCode.LOGIN_FAILED
|
||||
@ -111,7 +112,9 @@ class AuthControllerTest(
|
||||
val invalidMemberId: Long = -1L
|
||||
|
||||
every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId
|
||||
every { memberRepository.findByIdOrNull(invalidMemberId) } returns null
|
||||
every {
|
||||
memberFinder.findById(invalidMemberId)
|
||||
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
|
||||
|
||||
Then("에러 응답을 받는다.") {
|
||||
val expectedError = AuthErrorCode.MEMBER_NOT_FOUND
|
||||
@ -134,7 +137,7 @@ class AuthControllerTest(
|
||||
} returns 1L
|
||||
|
||||
every {
|
||||
memberRepository.findByIdOrNull(1L)
|
||||
memberFinder.findById(1L)
|
||||
} returns MemberFixture.create(id = 1L)
|
||||
|
||||
Then("정상 응답한다.") {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user