Spring Security 는 인증, 인가 그리고 일반적인 보안 공격 방어 기능을 구현한 스프링 표준 라이브러리입니다. Spring Security 는 타 라이브러리 보다 복잡한 아키텍쳐 구조를 가지고 있고, 공식 문서에서도 아키텍쳐의 일부만 안내하기에 라이브러리를 이해 및 활용하기에 어려움이 있습니다. 이 글에서는 Spring Security 6.2.3 버전의 Servlet 코드를 분석해 아키텍처를 깊게 탐험하는 시간을 가져보겠습니다.


Spring MVC 는 서블릿(톰캣)을 이용해서 클라이언트의 요청을 처리합니다. 클라이언트 요청이 들어오면, 스레드를 생성하고 내부에 서블릿 컨테이너 를 생성합니다. 서블릿 컨테이너 에는 다수의 필터 와 하나의 서블릿 이 포함되어 있습니다.
서블릿 : 요청을 처리하는 인터페이스 입니다. 대표적인 구현체로 DispatcherServlet 이 있습니다.
필터 : 요청이 처리되기 전, 요청을 수정하거나 요청이 다음 과정으로 넘어가지 못하도록 제어 하는 인터페이스 입니다.
서블릿은 웹 요청을 처리하기 좋은 인터페이스이지만, 스프링 프레임워크와는 독립적인 설계를 가져서 스프링과 연결하기에는 특별한 필터가 필요합니다.
DelegatingFilterProxy 는 스프링 프레임워크와 서블릿 인터페이스를 연결할 수 있는 특별한 필터입니다.

org.springframework.boot:spring-boot-starter-security 라이브러리가 등록되었다면, 서버를 시작할 때 자동으로 DelegatingFilterProxy 가 등록됩니다. 아래 함수 스택을 보면, TomcatStarter.onStartup 함수가 실행되었을때, DelegatingFilterProxy 생성자가 호출되는 것을 볼 수 있습니다.

이를 이용해 등록된 빈을 호출해 필터에 적용할 수 있습니다. Spring Security 에서는 보안을 위한 필터를 빈으로 정의합니다.
그런데, 보안 정책은 여러 가지가 될 수 있습니다. 예를 들어, /user/** API 는 사용자 인증을, /admin/** 는 관리자 인증을 그리고 /public/** 의 경우에는 인증이 적용되지 않아야 합니다. 즉, 여러 개의 보안 정책 과 이 보안 정책 중 적절한 보안 정책을 선택 하는 기능이 필요합니다.
DelegatingFilterProxy 의 다음 동작을 확인하기 앞서, 보안 정책 은 어떻게 정의할 수 있을까요? 예를 들어, 다음과 같은 관리자 보안 정책이 있다고 합시다.
SecurityFilterChain 를 제공합니다. 이를 이용해 복잡한 정책을 하나로 묶어 사용할 수 있습니다. 또한, 보안 정책이 어떤 HTTP 요청에서 처리되어야 하는지 도 정의할 수 있습니다.public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
다시 DelegatingFilterProxy 동작 과정으로 돌아갑시다. DelegatingFilterProxy 는 적절한 보안 정책을 선택 하는 FilterChainProxy 빈을 호출해 HTTP 요청을 처리하도록 합니다.

아래는 FilterChainProxy 에 있는 코드 중 적절한 필터를 호출하는 부분입니다. SecurityFilterChain.matches 함수를 이용해 적절한 필터를 찾는 모습을 볼 수 있습니다.
private List<Filter> getFilters(HttpServletRequest request) {
int count = 0;
Iterator var3 = this.filterChains.iterator();
SecurityFilterChain chain;
do {
if (!var3.hasNext()) {
return null;
}
chain = (SecurityFilterChain)var3.next();
if (logger.isTraceEnabled()) {
++count;
logger.trace(LogMessage.format("Trying to match request against %s (%d/%d)", chain, count, this.filterChains.size()));
}
} while(!chain.matches(request));
return chain.getFilters();
}
여기까지가 Spring Security 의 기본 설정입니다. 이를 활용해, 인증, 인가 그리고 보안 공격 방어를 구현할 수 있습니다. 다음 포스트에서는 인증 과정에 대해 깊게 다루어 보도록 하겠습니다.