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 + } +}