지난번 포스팅에서 커스텀 스프링 필터의 오류를 작성하였으니 이번 포스팅에서는 스프링 필터 구조에 대해서 자세하게 적고자 합니다.
스프링 필터에 대해서 설명하기 전, 서블릿과 서블릿 컨테이너에 대해서 간략하게 요약해보았습니다. 해당 개념이 모호하신 분들은 한번 읽고 스프링 필터에 대해서 읽어주세요.
서블릿이란
서블릿이란 Dynamic Web Page를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술이다. 웹을 만들 때 다양한 요청과 응답이 있고 이러한 요청과 응답을 간단한 메서드 호출로 처리해주는 기술이 서블릿의 역할이다.
서블릿 컨테이너란
서블릿을 담고 관리해주는 컨테이너이다. 서블릿 컨테이너는 구현되어 있는 서블릿 클래스의 규칙의 맞게 서블릿을 관리해준다.
클라이언트에서 요청을 하면 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체를 생성하여 서블릿 객체를 호출한다. 개발자는 Request, Response 객체에 담겨있는 HTTP 정보를 꺼내서 사용하면 된다.
톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다. 서블릿 객체는 일반적으로 싱글톤으로 관리되는데 이는 요청이 올 때마다 생성하는 것이 비효율적이기 때문이다. 서블릿은 최초 로딩 시점에 서블릿 객체를 미리 만들어두고 이를 재활용하며, 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근하게 된다. 따라서 공유 변수 사용에 주의해야 한다.
또한, 서블릿 컨테이너가 종료되면 서블릿도 종료가 되며, 서블릿 컨테이너는 동시 요청을 위한 멀티 쓰레드 처리도 지원한다.
일반적으로 우리가 WAS를 직접 구현하면 TCP/IP 연결 관리, 소켓 연결 관리, HTTP request 메시지 파싱, HTTP response 메시지 작성 등 많은 사전 과정을 구현해야 한다. 그러나, Servlet을 지원하는 WAS를 사용하게 되면 이러한 과정을 대신 수행해주기 때문에 개발자는 비즈니스 로직에만 집중할 수 있다.
서블릿 필터란
필터는 서블릿 실행 전, 후에 어떤 작업을 하고자 할 때 사용된다. 쉽게 생각하면 서블릿 컨테이너와 서블릿 객체 사이에 필터들이 순차적으로 놓여져 수행된다.
일반적으로 스프링에서 필터를 구현하고자 한다면 SpringSecurity 를 이용하실 텐데요. 이 스프링 시큐리티의 내부 구조 및 동작 방식을 설명하고자 합니다.
스프링 시큐리티 필터(FilterChainProxy)
스프링 시큐리티는 사용하고자 하는 FilterChain들을 ServletContainer 기반의 필터 위에서 동작시키기 위해서 DelegatingFilterProxy 클래스를 사용합니다. 이 DelegatingFilterProxy는 표준 서블릿 필터를 구현하고 있어 서블릿 컨테이너에 등록되지만, Filter를 구현하고 있는 스프링 빈에게 필터 작업을 위임합니다.
아래는 공식문서에 나와있는 FilterChainProxy 설명과 그림입니다. 공식문서에서 보여지고 있는 FilterChain이 ServletContainer가 관리하는 필터이며 이는 ApplicationFilterChain입니다.
Spring Security’s Servlet support is contained within FilterChainProxy. FilterChainProxy is a special Filter provided by Spring Security that allows delegating to many Filter instances through SecurityFilterChain. Since FilterChainProxy is a Bean, it is typically wrapped in a DelegatingFilterProxy.
DelegatingFilterProxy가 표준 서블릿 컨테이너와 Spring IOC 컨테이너의 다리 역할을 하고 있습니다. 다시 말하면, DelegatingFilterProxy는 서블릿 필터이고, Spring IOC 컨테이너가 관리하는 FilterChainProxy(Bean)을 지니며 이 객체 안에서 Security와 관련된 일들이 벌어집니다.
이 FilterChainProxy 역시 처리를 위임하기 위한 SecurityFilterChain을 들고 있는데요, SecurityFilterChain을 담도록 선언돼 있는 필드는 List <>이며 각각 다른 SecurityFilter들이 들어있는 SecurityFilterChain들이 담길 수 있습니다.
SecurityFilterChain이 여러 개 등록되어 있을 경우, FilterChainProxy는 endpoint 등에 따라서 어떤 SecurityFilterChain을 적용할지 결정합니다. 여기서 중요한 것은 첫번째로 매치된 필터만 작동을 한다는 것입니다.
만약 위 그림처럼 필터가 등록되어 있을 경우를 예시로 들어보겠습니다. 만약 요청 URL이 /api/messages/ 이면 SecurityFilterChain(0)이 처음으로 매치되어 SecurityFilterChain(n)은 작동하지 않습니다.
또한, 위 그림에서 알 수 있듯이 SecurityFilterChain(0)을 구성하고 있는 SecurityFilter는 3개 이고, SecurityFilterChain(n)의 SecurityFilter는 4개 인 것처럼 각 SecurityFilterChain은 독립적이고 개별적으로 분리되어 작동됩니다. 만약 특정 요청에 대하여 스프링 시큐리티가 무시되길 원한다면 SecurityFilterChain에 저장된 Filter를 0개로 지정할 수 있습니다.
'웹 어플리케이션 공부 > Spring 공부' 카테고리의 다른 글
Spring으로 개발하며 맞닥뜨린 CORS! (1) | 2021.12.08 |
---|---|
MongoDB 와 Spring 연동설정 (0) | 2020.05.05 |
Spring 공부 - 초기 설정 (0) | 2019.08.16 |