hoony's web study

728x90
반응형

1. 개요

이번엔 코틀린 스프링부트에서 Interceptor를 적용하는 방법을 알아볼건데요.

보통, headerJWT Token 혹은 임의의 사용자 정의 키값을 통해 API 사용권한을

검증하는 방법을 많이들 사용하시는데요.

이때, 중복된 코딩과 소스를 방지하기 위해 Interceptor의 preHandle()

응용할 수 있습니다.

하지만, 저의 경우 ExceptionHandling과 함께 Exception을 Throw해서

처리하려 하였으나 중간에 어려움이 있었는데요.

그건 바로, preHandle() 에서 Throw된 Exception이 @ControllerAdvice 와 @ExceptionHandler

어노테이션이 걸려있는 메서드에 잡히지 않는다는 것입니다.

이는 예제 소스와 함께 확인해보시죠!

 

2. 예제

 

- 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 하도록 되어있습니다.

728x90

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading