인증 예외 핸들러 등록하기

Nicky·2024년 3월 16일
0
post-thumbnail

이번 포스팅은 예외 핸들러를 등록하는 과정을 다뤄보겠다.

인증/인가 예외

Spring Security에서는 기본적으로 2가지 예외(인증/인가)에 대한 처리를 한다. 각각 어떻게 처리되는지 알아보자.

AuthenticationException

AuthenticationException은 인증 과정에서 유효하지 않은 자격 증명이 제출될 때(로그인 실패) 발생한다.

  • UsernamePasswordAuthenticationFilter에서 자격증명이 유효하지 않을 경우 AuthenticationException을 발생시킴
  • ExceptionTranslationFilter는 예외를 캐치하고 AuthenticationEntryPoint를 통해 처리.

AccessDeniedException

AccessDeniedException은 인증된 사용자가 자신이 권한이 없는 리소스에 접근할 때 발생한다.

  • FilterSecurityInterceptor는 접근 결정을 내리는 필터로, 권한이 충분하지 않을 경우 AccessDeniedException을 발생시킴
  • ExceptionTranslationFilter는 예외를 캐치하고 AccessDeniedHandler를 통해 처리.

이제 각 예외들이 AuthenticationEntryPointAccessDeniedHandler를 통해 처리됨을 알게 되었다.

에러 상태 코드

커스텀 예외 핸들러를 등록하기 전에, 먼저 인증 관련 에러 상황에 쓰이는 HTTP 상태 코드에 대해 알아보자.

나는 기본 핸들러가 아닌 커스텀 핸들러를 통해 각 인증 예외 상황 발생시 적절한 에러 응답을 보내는 목적을 갖고 있다. 이제 각 예외 상황에 대해서 어떻게 처리할지에 대해 생각해보자.

401 Unauthorized

401 에러는 인증되지 않음을 나타내는 에러이다. 설정한 Security FilterChain에 따라 클라이언트가 유효한 토큰을 갖고 API 요청을 가져오지 않으면 해당 상태 코드를 보낼 것이다.

403 Forbidden

403 에러는 금지됨을 나타내는 에러이다. 401 에러가 인증이 안됨을 나타내는 상태 코드라면, 403 에러는 인증은 되었지만 권한이 없는 경우를 뜻한다.

FilterChain 구성시 http.authorizeRequests 메서드를 통해 특정 경로에 대해 권한 설정을 할 수 있는데.. 아래 코드의 경우 사용자가 HOST 권한이 없다면 403 에러를 받게 될 것이다.

.requestMatchers(antMatcher(HttpMethod.POST, "/api/posts")).hasRole("HOST")

이제 각 예외 상황들에 적절한 상태 코드를 보내 보자.

커스텀 핸들러

각 핸들러들은 응답으로 적절한 상태코드와 메시지를 보내게 될 것이다.

JwtAuthenticationEntryPoint

// 인증 실패 (401)
@RequiredArgsConstructor
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private final ResponseWriter responseWriter;

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException authenticationException) throws IOException {
        responseWriter.writeErrorResponse(response, SC_UNAUTHORIZED, UNAUTHORIZED.getMessage());
    }
}

JwtAccessDeniedHandler

// 인증이 되었지만 접근 권한이 없는 경우 (403)
@RequiredArgsConstructor
public class JwtAccessDeniedHandler implements AccessDeniedHandler {

    private final ResponseWriter responseWriter;

    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException accessDeniedException) throws IOException {
        responseWriter.writeErrorResponse(response, SC_FORBIDDEN, NO_AUTHORITY.getMessage());
    }
    
}

핸들러 등록

구현한 핸들러들은 FilterChain에서 exceptionHandling 메서드를 통해 등록할 수 있다.

.exceptionHandling()
.accessDeniedHandler(new JwtAccessDeniedHandler(responseWriter))
.authenticationEntryPoint(new JwtAuthenticationEntryPoint(responseWriter))
profile
코딩 연구소

0개의 댓글

관련 채용 정보