From c79a4bdd1f063498c5651c615bd94a6a4a8488fb Mon Sep 17 00:00:00 2001 From: pricelees Date: Thu, 11 Sep 2025 16:58:29 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=90=9C?= =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=20=EC=A0=84=EC=9A=A9=20API=EC=97=90=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=A0=20=EC=83=88=EB=A1=9C=EC=9A=B4=20Int?= =?UTF-8?q?erceptor=20=EB=B0=8F=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/web/support/AuthAnnotations.kt | 4 ++ .../support/interceptors/UserInterceptor.kt | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt diff --git a/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt b/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt index 2fb7af52..55490e4b 100644 --- a/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt +++ b/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt @@ -19,3 +19,7 @@ annotation class MemberId annotation class AdminOnly( val privilege: Privilege ) + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class UserOnly diff --git a/src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt b/src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt new file mode 100644 index 00000000..c350f2ec --- /dev/null +++ b/src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt @@ -0,0 +1,50 @@ +package roomescape.auth.web.support.interceptors + +import io.github.oshai.kotlinlogging.KLogger +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.slf4j.MDC +import org.springframework.stereotype.Component +import org.springframework.web.method.HandlerMethod +import org.springframework.web.servlet.HandlerInterceptor +import roomescape.auth.business.CLAIM_TYPE_KEY +import roomescape.auth.exception.AuthErrorCode +import roomescape.auth.exception.AuthException +import roomescape.auth.infrastructure.jwt.JwtUtils +import roomescape.auth.web.support.MDC_MEMBER_ID_KEY +import roomescape.auth.web.support.UserOnly +import roomescape.auth.web.support.accessToken +import roomescape.common.dto.PrincipalType + +private val log: KLogger = KotlinLogging.logger {} + +@Component +class UserInterceptor( + private val jwtUtils: JwtUtils +) : HandlerInterceptor { + + override fun preHandle( + request: HttpServletRequest, + response: HttpServletResponse, + handler: Any + ): Boolean { + if ((handler !is HandlerMethod) || (handler.getMethodAnnotation(UserOnly::class.java) == null)) { + return true + } + + val token: String? = request.accessToken() + val userId = jwtUtils.extractSubject(token).also { id -> MDC.put(MDC_MEMBER_ID_KEY, id) } + + jwtUtils.extractClaim(token, CLAIM_TYPE_KEY).also { + if (it != PrincipalType.USER.name) { + log.warn { "[UserInterceptor] 관리자의 회원 API 접근: id=${userId}" } + throw AuthException(AuthErrorCode.ACCESS_DENIED) + } + } + + log.info { "[AuthInterceptor] 인증 완료. userId=$userId" } + + return true + } +}