Spring security에서 Jwt 인증 과정에서 발생하는 예외처리를 담당할 JwtAuthenticationEntryPoint를 구현하려고 했다.
역시나 그림일기 서비스가 굉장히 깔끔하게 구현이 된 것 같아서 따라하려고 봤더니 일반적으로 구현하는 방식과 차이가 있는 것을 발견했다.
JwtAuthenticationEntryPoint는 보통 AuthenticationEntryPoint를 implements 해서 구현한다.
그런데 그림일기 서비스는 OncePerRequestFilter를 extends 해서 JwtAuthenticationEntryPoint를 구현했다.
왜 그런가 살펴봤더니 AuthenticationEntryPoint를 implements 하면 AuthenticationException에 대한 예외처리만 할 수 있기 때문이었다.
단순히 인증이 실패했다는 예외처리만 하는 게 아니라, 만료된 토큰인지, 유효하지 않은 토큰인지 커스텀 익셉션을 구현해 세부적으로 나누어 처리하려면 OncePerRequestFilter를 extends 하는 게 더 나았던 것이다.
하지만 고민이 생겼다. claude는 spring security에서 기본적으로 정의된 흐름을 따르는 것이 좋다고 답변을 해주기 때문이다.
인터넷에서 검색했을 때 나오는 글들을 봐도 AuthenticationEntryPoint를 implements 하는 경우가 대부분이기도 했다.
챗지피티한테도 물어보며 답변을 읽다보니 결국 이것도 선택의 문제인 것 같다.
--> 라고 생각했는데...
https://velog.io/@hellonayeon/spring-boot-jwt-expire-exception
이 글을 보니 세부적으로 예외처리를 하는 게 맞아보인다;; 적어도 만료된 토큰에 대한 예외처리만이라도.. 왜냐면 토큰이 만료된 경우에 refresh token 요청을 해야하기 때문에...
원래는 프론트에서 401인 경우 무조건 refresh token 요청을 보내보게 했었는데
error code를 가지고 만료된 토큰인 경우에만 refresh token 요청을 보내게 하는 게 맞아 보인다.
또 블로그를 보니 JwtExceptionFilter로 네이밍을 하는 게 나아보여 나도 JwtExceptionFilter로 클래스명을 지었다.
아래는 그래도 고민한 흔적들.....
JwtAuthenticationEntryPoint
를 구현할 때 AuthenticationEntryPoint
와 OncePerRequestFilter
중 어떤 것을 선택할지는 애플리케이션의 구조와 요구 사항에 따라 달라집니다. 각각의 선택에 따른 장단점이 있으니 이를 고려해 보면 좋을 것 같습니다.
AuthenticationEntryPoint
를 사용하는 경우:AuthenticationEntryPoint
는 Spring Security에서 인증 실패에 특화된 인터페이스로, 간단하게 인증 실패 처리를 정의할 수 있습니다.OncePerRequestFilter
를 사용하는 경우:AuthenticationEntryPoint
를 사용하는 것이 더 적절해 보입니다. 이 경우 Spring Security의 표준적인 흐름을 따르기 때문에 간결하고 명확하게 인증 실패를 처리할 수 있습니다.OncePerRequestFilter
를 사용하는 것이 맞습니다. 특히, JWT 토큰 검증, 다양한 에러 처리, 응답 형식 커스터마이징 등을 한 곳에서 처리할 수 있기 때문에 더 유연하게 동작합니다.당신이 현재 보고 있는 코드의 구조는 다양한 인증 및 예외 상황을 처리하려는 복잡한 요구 사항에 맞춰져 있는 것으로 보이므로, OncePerRequestFilter
가 적절한 선택으로 보입니다.
Spring Security에서 인증 예외 처리는 AuthenticationException
을 기반으로 설계되어 있으며, 이것은 의도적인 설계입니다. Spring Security는 표준화된 인증 흐름을 통해 일관성 있게 예외를 처리하고, 보안을 유지하려는 목적을 가지고 있습니다. 하지만 이를 확장하거나 커스터마이징하는 것도 가능하며, 이 부분에서 선택이 중요해집니다.
Spring Security는 기본적으로 인증 과정에서 발생하는 모든 예외를 AuthenticationException
으로 처리합니다. 이 예외는 인증 과정에서 문제가 발생했을 때 발생하며, 다양한 인증 관련 예외(예: 비밀번호 오류, 토큰 오류 등)의 상위 클래스입니다.
AuthenticationManager
를 통해 인증을 시도합니다.AuthenticationException
이 발생합니다.AuthenticationEntryPoint
에 의해 처리되어, 인증되지 않은 사용자의 경우 401(Unauthorized) 응답을 반환합니다.AuthenticationException
만 처리하도록 설계된 이유AuthenticationException
하나로 모든 인증 관련 예외를 처리함으로써 코드의 일관성과 단순성을 유지합니다.AuthenticationException
을 사용하면 모든 인증 예외를 하나의 구조로 처리할 수 있으며, 이를 통해 전반적인 인증 처리 로직을 단순화할 수 있습니다.Spring Security가 기본적으로 AuthenticationException
만 처리하도록 설계되었지만, 이 기본 동작을 커스터마이징하는 것도 가능합니다. 예를 들어, JWT를 사용하는 경우 토큰이 만료되거나 잘못된 토큰 형식을 제공하는 등의 다양한 예외 상황을 세부적으로 처리할 필요가 있을 수 있습니다.
특정 인증 방식에 대한 맞춤 예외 처리: JWT 같은 경우, 다양한 토큰 관련 예외가 발생할 수 있습니다(토큰 만료, 서명 오류, 부적절한 토큰 등). Spring Security의 기본 AuthenticationException
구조는 이러한 세부 상황을 충분히 표현하지 못할 수 있습니다. 그래서 더 세부적인 예외를 다루기 위해서는 OncePerRequestFilter
처럼 커스터마이징된 처리가 필요할 수 있습니다.
세부적인 에러 메시지 제공: 때로는 API 클라이언트에게 더 구체적인 에러 메시지를 반환해야 할 수 있습니다. 예를 들어, "토큰 만료" 또는 "유효하지 않은 토큰" 같은 에러를 클라이언트에게 명확하게 전달해야 할 필요가 있는 경우, Spring Security의 기본 인증 예외 처리 흐름을 확장해야 합니다.
OncePerRequestFilter
를 사용하여 JWT 토큰의 다양한 예외를 처리하는 것은 타당해 보입니다. 다만, 이 경우에도 필요 이상으로 세부적인 정보를 노출하지 않도록 주의해야 합니다.즉, Spring Security의 표준 설계를 따르는 것은 일반적으로 권장되지만, 현재의 JWT와 관련된 복잡한 요구 사항에서는 커스터마이징이 필요한 경우가 많습니다.