이번엔 코틀린 스프링부트에서 Interceptor를 적용하는 방법을 알아볼건데요.
보통, header에 JWT Token 혹은 임의의 사용자 정의 키값을 통해 API 사용권한을
검증하는 방법을 많이들 사용하시는데요.
이때, 중복된 코딩과 소스를 방지하기 위해 Interceptor의 preHandle()을
응용할 수 있습니다.
하지만, 저의 경우 ExceptionHandling과 함께 Exception을 Throw해서
처리하려 하였으나 중간에 어려움이 있었는데요.
그건 바로, preHandle() 에서 Throw된 Exception이 @ControllerAdvice 와 @ExceptionHandler
어노테이션이 걸려있는 메서드에 잡히지 않는다는 것입니다.
이는 예제 소스와 함께 확인해보시죠!
- NoAuthHeaderException.kt
class NoAuthHeaderException(
var code: String,
var message: "접근 권한이 없습니다.",
var status: HttpStatus.UNAUTHORIZED
)
- ControllerAdvice.kt , authExceptionHandle()
/**
* ApiKey Header 관련 Exception 처리
*/
@ExceptionHandler(value = [NoAuthHeaderException::class])
fun authExceptionHandle(e: NoAuthHeaderException, request: HttpServletRequest): ResponseEntity<Any> {
val errorResp: MutableMap<String, Any?> = hashMapOf(
"code" to e.code,
"message" to e.message,
"status" to e.status
)
return ResponseEntity.status(e.status.value()).body(errorResp)
}
- SampleController
@RestController
@RequiredArgsConstructor
class CmmnController(val objectMapper: ObjectMapper) {
/**
* Interceptor Exception 처리용
*/
@RequestMapping(value = ["/keyerror"], method = [RequestMethod.GET, RequestMethod.POST])
fun error(request: HttpServletRequest) {
val exception = request.getAttribute("exception")
when {
"NoAuthHeaderException".equals(exception) -> {
throw NoAuthHeaderException()
}
}
}
}
- ApiValidationInterceptor.kt
@Component
@RequiredArgsConstructor
class ApiValidationInterceptor(): AsyncHandlerInterceptor {
/**
* api key 검증
*/
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
val apiKeyHeader = if (request.getHeader("x-perm-key") == null) request.getHeader("X-Api-Key") else request.getHeader("x-api-key")
if (apiKeyHeader == null) {
request.setAttribute("exception", "NoAuthHeaderException")
request.getRequestDispatcher("/keyerror").forward(request, response)
System.out.println("request = " + request)
return false
} else {
// TODO : DB를 통해 해당 ApiKey값의 여부를 확인
}
return true
// return super.preHandle(request, response, handler)
}
}
위의 예제 코드를 보시면, 약간의 꼼수(?) 를 이용하였습니다.
Interceptor의 preHandle() 과 @ExceptionHandler, @ControllerAdvice 둘의 scope가
다름에 따라, 임의의 컨트롤러 맵핑을 통해 exception을
의도한대로 핸들링 해주도록 처리한 예제입니다.
만약 저렇게 처리하지 않고 throw를 하신다면, springboot에서 {context-path}/error
를 기본적으로 forwarding 하도록 되어있습니다.
[Kotlin]Lift return out of if 란 무엇인가? (0) | 2023.11.21 |
---|---|
[Kotlin] firstOrNull 에 대한 정리 (1) | 2023.10.26 |
[Kotlin] mutableListOf 함수에 대한 예제 (0) | 2023.10.25 |
[Kotlin] 엘비스 연산자 (Elvis Operation) (0) | 2023.08.31 |
[Kotlin] SpringBoot 에서 다중 DataSource 적용 (0) | 2023.04.26 |