Backend/Spring Security

Spring Security의 예외 처리 방식

olsohee 2024. 1. 22. 15:47

ExceptionTranslationFilter

Spring Security는 ExceptionTranslationFilter를 통해 인증 예외(AuthenticationException)와 인가 예외(AccessDeniedException)를 적절하게 처리하고 원하는 형태의 HTTP 응답을 줄 수 있다.

 

ExceptionTranslationFilter는 다음과 같이 SecurityFilterChain에 속해 있는 필터 중 하나로, 실행 흐름은 다음과 같다.

  1. ExceptionTranslationFilter는 FilterChain.doFilter(request, response)를 통해 이어진 필터들을 호출한다.
  2. 만약 AuthenticationException이 발생한 경우, 다음을 실행한다.
    1. SecurityContextHolder가 지워진다.
    2. HttpServletRequest는 인증 성공시 원래 요청을 다시 수행하기 위해 저장된다.
    3. 클라이언트에게 인증 정보를 요청하는 HTTP 응답을 하기 위해 AuthenticationEntryPoint가 사용된다.
  3. 그렇지 않고 AccessDeniedException이 발생한 경우, 다음을 실행한다.
    1. AccessDeniedException를 처리하기 위해 AccessDeniedHandler가 호출된다.
  4. 만약 어플리케이션이 AuthenticationException나 AccessDeniedException을 발생시키지 않으면, ExceptionTranslationFilter는 아무것도 하지 않는다.

인증 예외와 인증 예외 처리

AuthenticationException

Spring Security는 인증과 관련된 예외 상황에서 AuthenticationException을 발생시킨다. AuthenticationException은 다음과 같이 추상 클래스이고, 여러 AuthenticationException 하위 클래스가 있다.

public abstract class AuthenticationException extends RuntimeException {

	public AuthenticationException(String msg, Throwable cause) {
		super(msg, cause);
	}

	public AuthenticationException(String msg) {
		super(msg);
	}

}

 

AuthenticationException의 하위 클래스 중 하나로, InsufficientAuthenticationException이 있다. InsufficientAuthenticationException는 인증이 필요한 리소스에 인증 되지 않은 사용자가 접근하려고 할 때 발생한다.

public class InsufficientAuthenticationException extends AuthenticationException {

	public InsufficientAuthenticationException(String msg) {
		super(msg);
	}
    
	public InsufficientAuthenticationException(String msg, Throwable cause) {
		super(msg, cause);
	}

}

AuthenticationEntryPoint

그리고 우리는 AuthenticationEntryPoint를 통해 사용자에게 인증 정보를 요청하는 HTTP 응답을 내릴 수 있다. AuthenticationEntryPoint는 다음과 같이 인터페이스 형태이고, 파라미터로 AuthenticationException을 받는다.

public interface AuthenticationEntryPoint {

	void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
			throws IOException, ServletException;

}

 

따라서 AuthenticationEntryPoint의 구현체를 만들고 등록하면, AuthenticationException 예외가 발생했을 때 AuthenticationEntryPoint 구현체의 commence() 메소드가 호출된다. 따라서 우리는 commence() 메소드의 구현을 통해 원하는 로직을 작성해주면 된다. 

인가 예외와 인증 예외 처리

AccessDeniedException

Spring Security는 인증과 관련된 예외 상황에서 AccessDeniedException을 발생시킨다.

public class AccessDeniedException extends RuntimeException {

	public AccessDeniedException(String msg) {
		super(msg);
	}

	public AccessDeniedException(String msg, Throwable cause) {
		super(msg, cause);
	}

}

 

AccessDeniedHandler

AuthenticationEntryPoint와 마찬가지로 AccessDeniedHandler를 통해 사용자에게 원하는 HTTP 응답을 내릴 수 있다. AccessDeniedHandler는 다음과 같이 인터페이스 형태이고, 파라미터로 AccessDeniedException을 받는다.

public interface AccessDeniedHandler {

	void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
			throws IOException, ServletException;

}

 

따라서 AccessDeniedHandler의 구현체를 만들고 등록하면, AccessDeniedException 예외가 발생했을 때 AccessDeniedHandler 구현체의 commence() 메소드가 호출된다. 따라서 우리는 commence() 메소드의 구현을 통해 원하는 로직을 작성해주면 된다.


Reference