Spring Security
는 Servlet Filters
를 기반으로 동작한다.
Spring Security
는 인증, 권한 부여 및 보호를 제공하는 프레임워크이다.
전체적인 구조는 위와 같다.
plugins {
id 'io.spring.dependency-management' version "1.0.10.RELEASE"
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
그래서 필터의 역할을 먼저 아는것이 중요한데,
Filter
영어 단어만 봐도 뭔가를 필터로 걸러주는 느낌이 난다.
업무중에 통신 하나하나의 로그를 다 찍는 과정을 Filter
를 통해서 구현했던 경험이 있다.
이 필터를 줄줄이 연결하면 FilterChain
이 되는 것이다.
다음은 스프링 공식문서에서 FilterChain
의 구조를 가져왔다.
클라이언트는 서버에 요청을 보내고 컨테이너는 요청 URI
를 기반으로 HttpServletRequest
를 처리하는 필터와
필터체인을 생성한다. Spring MVC
에서의 Servlet
은 DispatcherServlet
이 된다.
Filter
인터페이스를 구현하면 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
메소드를 구현해주어야 한다.
chain.doFilter()
를 호출하면 다음 필터를 차례대로 수행하는 것이다.
이렇게 필터들이 쭉 연결되어 기능을 수행한다고 생각하면 된다.
Spring
은 Servlet 컨테이너
의 라이프사이클과
Spring
의 ApplicationContext
사이의 연결을 허용하는
DelegatingFilterProxy
라는 필터를 제공한다.
이 필터는 Servlet Filter
로 애플리케이션 컨텍스트에서 요청한 것을 스프링 컨테이너에 생성된
Bean Filter
를 찾고 그 필터를 호출한다.
DelegatingFilterProxy
는 컨테이너가 시작되기 전에 필터를 등록해야 하기 때문에 중요하다.
Spring Security
의 서블릿 지원은 FilterChainProxy
에 포함되어 있다.
FilterChainProxy
는 SecurityFilterChain
을 통해 여러 필터 인스턴스에 위임할 수 있도록
시큐리티에서 제공하는 특수 필터이다.
FilterChainProxy
는 Bean
이라서 DelegatingFilterProxy
안에 포함된다.
이제보니 구조가 좀 잡혀가는것 같다.
클린코드와 자바의 정석을 읽었더니 시큐리티 아키텍처가 이해되는건 무엇일까.... 🤔🤔🤔
SecurityFilterChain
은 클라이언트에서 필터를 돌다가 DelegatingFilterProxy
에 들어온 요청을
받아서 이 요청에 대해 처리해야 하는 Security Filter
를 찾아 수행한다.
핵심인 시큐리티 필터이다. 이 필터는 SecurityFilterChain API
를 사용해
FilterChainProxy
에 삽입된다. 이 필터들은 순서가 중요하다.
필터의 순서를 알 필요는 없다.
근데 알아두면 유용하게 사용할 수는 있다.
필터에는 다음과 같은 필터들이 존재하고 위에서 아래로 순서가 매겨져 있다.
UsernamePasswordAuthenticationFilter
DigestAuthenticationFilter
BasicAuthenticationFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
블럭이 쳐져있는 필터들을 유의해서 더욱 살펴봐야 하겠다.
위에서 ExceptionTranslationFilter
를 사용하면 AccessDeniedException
이나,
AuthenticationException
을 HTTP Response로 변환할 수 있다.
FilterChain.doFilter()
로 나머지 애플리케이션을 호출한다.AuthenticationException
이 발생한 경우에 인증을 진행한다.RequestCache
에 사용자를 저장하고 이 캐시를 사용하여 원래 요청을 쭉 진행한다.AccessDeniedException
이 발생하게 되면 액세스는 거부되고, AccessDeniedHandler
는 이 예외를 처리하기 위해 호출된다.이 설정이 AccessDeniedException
과 AuthenticationException
에 대한 예외처리가 없다면
ExceptionTranslationFilter
는 아무것도 수행하지 않는다.
여기까지가 일단 스프링 시큐리티의 기본적인 흐름이다.
다음 포스팅에서는 인증(Authentication)
에 대해서만 쭉 다뤄보는것으로 하겠다.
어렴풋이 알고 있는 기본값들에 대해서만 사용할게 아니라 입맛에 따라 커스텀하며 필터를 작업해주는 것이
개발자의 역량이라고 생각한다. 이게 뒷받침되려면 당연히 이런 공식문서를 읽어보는게 답이다.
전체적인 아키텍처의 흐름을 알아야 잘 설계할 수 있다.
아무튼 이 아키텍처를 공부함으로써 어제의 나보다는 오늘이 더 성장했다.
업무나 프로젝트에 들어간 시큐리티에 대한 코드를 보면 지금보다 더 이해할거라고 자신한다 🔥🔥🔥🔥