Programming/Spring Boot

ExceptionTranslationFilter과 SecurityInterceptor

Jan92 2022. 8. 1. 23:20
반응형

ExceptionTranslationFilter, FilterSecurityInterceptor, MethodSecurityInterceptor

해당 포스팅은 Spring Security에서 인증(Authentication)과 인가(Authorization)에 대한 예외 처리를 담당하는 ExceptionTranslationFilter과 해당 필터에 이어서 동작하며, 권한을 검사하는 FilterSecurityInterceptor, MethodSecurityInterceptor의 동작 과정에 대해서 살펴본 내용입니다.

 

 

 

- ExceptionTranslationFilter

먼저 ExceptionTranslationFilter의 경우 스프링 시큐리티의 filter chain에서 인증과 인가에 대한 Exception을 터트리는 역할을 하는데요. (AccessDeniedException and AuthenticationException)

주석에서 볼 수 있는 것처럼, 해당 필터는 Java와 HTTP 응답 사이에 브릿지 역할을 하며, 실제 보안에 직접적으로 참여하지는 않습니다.

 

 

doFilter() method

ExceptionTranslationFilter의 doFilter() 메서드를 살펴보면 try 부분에서 chain.doFilter() 메서드를 통해 다음 동작하는 Filter를 동작시키고, 여기서 발생하는 Exception(AuthenticationException || AccessDeniedException)을 잡아서 handleSpringSecurityException() 메서드를 통해 처리하게 되는데요.

 

try 부분의 chain.doFilter() 메서드를 통해 다음으로 동작하는 필터가 바로 이어서 살펴볼 SecurityInterceptor입니다.

 

 

 

- FilterSecurityInterceptor, MethodSecurityInterceptor

SecurityInterceptor는 Spring Security의 필터들 중에서 가장 마지막에 위치한 필터인데요. 접근 권한 즉, 인증된 사용자에 대한 인가를 검증하는 역할을 주로 합니다.

 

FilterSecurityInterceptorMethodSecurityInterceptor 두 가지가 있는 이유는 필터 단에서 발생하는 인가 검증을 하느냐, 메서드 단에서 발생하는 인가 검증을 하느냐의 차이인데요.

 

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/home").permitAll()
        .antMatchers("/user").hasAnyRole("USER", "ADMIN")
        .anyRequest().anthenticated();
}

이런 식으로 Filter를 통해 권한에 대한 검증을 진행한다면 FilterSecurityInterceptor가 동작하게 되며,

 

@PreAuthorize("hasRole('USER')")
@GetMapping("/user")
public String user() {
    return "/user";
}

@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public String admin() {
    return "/admin";
}

컨트롤러 단에서 @PreAuthorize, @Secured 등의 어노테이션으로 권한에 대한 검증을 진행하게 된다면 MethodSecurityInterceptor가 동작하게 되는 것입니다.

 

 

public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    ...
}

public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {
    ...
}

중요한 것은 이 두 클래스 모두 AbstractSecurityInterceptor라는 추상 클래스를 상속받았다는 것인데요.

 

 

MethodSecurityInterceptor의 invoke() 메서드

실제 동작 부분 역시 super.beforeInvocation(), super.finallyInvocation(), super.afterInvocation()처럼 상위에 있는 AbstractSecurityInterceptor의 메서드를 사용하여 동작하는 것을 볼 수 있습니다.

 

AbstractSecurityInterceptor에서 실제 권한을 확인하는 것은 AccessDecisionManager가 담당하며, 해당 객체의 decide() 메서드를 통해 동작하게 됩니다.

 

 

 

- 다시 ExceptionTranslationFilter

doFilter() method

동작 과정 중 조금 신기했던 부분은 인증(로그인)이 안된 사용자가 접근했을 때, AuthenticationException이 발생하는 것이 아니라 AccessDeniedException으로 먼저 발생한다는 점이었습니다. 이유는 anonymous로 Authentication 객체가 생성된 상태이기 때문인데요.

 

디버깅을 해보면, 인증(로그인)이 안된 사용자가 접근 시, securityException은 AccessDeniedException인 상태로 handleSpringSecurityException() 메서드가 동작하게 됩니다.

 

 

handleAccessDeniedException

이어지는 과정은 handleSpringSecurityException() 메서드를 거처 handleAccessDeniedException() 메서드가 동작하게 되는데요.

해당 메서드 내부에서 anonymous 여부를 확인하여 sendStartAuthentication() 메서드를 통해 처리되게 되는 것입니다.

 

 

 

< 참고 자료 >

 

세션을 사용한 스프링 시큐리티 구현(WebSecurityConfigurerAdapter deprecated)

Session을 사용한 아주 기본적인 스프링 시큐리티 코드를 정리한 내용입니다. 최근 WebSecurityConfigurerAdapter가 deprecated 되면서 해당 부분이 적용된 코드로 구현하였으며, 세부적인 내용을 모두 담기

wildeveloperetrain.tistory.com

 

 

Spring Security 시큐리티 동작 원리 이해하기 - 1

스프링 시큐리티 (Spring Security)는 스프링 기반 어플리케이션의 보안(인증과 권한, 인가)을 담당하는 스프링 하위 프레임워크입니다. 보안과 관련해서 체계적으로 많은 옵션들을 제공해주기 때문

wildeveloperetrain.tistory.com

반응형