Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save taekwon-dev/06ec9ec08e7738e0bae71f883ce95b60 to your computer and use it in GitHub Desktop.
Save taekwon-dev/06ec9ec08e7738e0bae71f883ce95b60 to your computer and use it in GitHub Desktop.

[Spring Security] - Servlet Application Architecture

Servlet Application 에서 Spring Security Framework의 동작 원리를 설명하는 글이다. Spring Security Architecture 원문을 그대로 직역하지 않고 이해 과정을 풀어가면서 작성 했다. 일부 지엽적인 부분은 제외 했고, 제외된 부분은 별도의 토픽으로 정리할 예정이다. 글 제목에서도 언급된 것 처럼 Servlet , Servlet Container 에 대한 이해를 기반으로 읽는 것을 추천한다.


| A Review of (Servlet) Filters

Spring Security’s Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. The picture below shows the typical layering of the handlers for a single HTTP request.

image [ 그림 1 ]

“Spring Security가 서블릿 필터를 기반으로 서블릿을 지원한다”

위 정의에서 알 수 있듯이 서블릿 애플리케이션에서 Spring Security 가 동작하는 상대적인 위치 및 원리를 이해하는데 있어서 가장 중요한 개념은 서블릿 필터 다.

클라이언트가 HTTP 요청을 보냈을 때 웹 서버는 해당 요청을 포워딩을 통해 서블릿 컨테이너에 전달하고, 서블릿 컨테이너는 해당 요청을 처리할 적절한 서블릿을 찾아 서블릿에 해당 요청을 전달한다. 이 때 [ 그림 1 ] 에서 볼 수 있듯이 서블릿에 도달하기 전 여러 필터를 사용할 수 있고, 필터가 여러 개인 점에서 필터 체인 이라 불린다. (이 필터 체인은 서블릿 컨테이너가 관리한다) (사용 예시 - 인증, 로깅 등)

필터 체인 에서 중요한 것은 각 필터가 적용되는 순서인데, 이는 서블릿에 도달하기 까지 과정이 모두 아래 방향으로 순차적으로 진행되기 때문이다. [ 그림 1 ] 에서는 Filter0Filter1Filter2 순서로 동작한다.

서블릿 필터 를 리뷰하면서 언급한 특징이 Spring Security 에서 어떻게 적용되는 지 확인해보자.


| DelegatingFilterProxy

어려워 보이는 이름에 낚이지 말자. DelegatingFilterProxy 는 하나씩 뜯어 보면 매우 친절한 이름을 갖고 있다.

Spring Security가 서블릿 필터를 기반으로 서블릿을 지원한다

위 정의를 기반으로, Spring Security 동작되는 상대적인 위치가 서블릿 필터 라는 것을 알 수 있었다.

image [ 그림 2 ]

[ 그림 1 ] 과 [ 그림 2 ] 를 보면, 필터 체인 중 한 자리가 DelegatingFilterProxy 로 대체된 것을 볼 수 있다. 그리고 그 속에 Bean Filter 0 이 포함되어 있다.

DelegatingFilterProxy 역할에 대해서 언급하기 전에 이름을 한 번 분석해보자. 가운데 위치한 Filter 를 제외하고 앞 뒤로 붙어 있는 두 단어 뜻은 아래와 같다.


  • Delegate (Delegating 의 동사) - 위임 시키다.
  • Proxy - 대리(인)

DelegatingFilterProxy무엇 을 위임시키고, 누구 의 대리 역할을 하는 지 이해하면 오히려 이름을 통해 역할을 쉽게 추론할 수 있다.

[ 그림 2 ] 에서 볼 수 있듯이 DelegatingFilterProxy서블릿 필터 중 한 자리를 차지하고 있다. Spring Security Framework 에서는 자신이 제공하는 필터를 클라이언트 요청이 서블릿에 도달하기 전에 호출되도록 하고 싶을 것이다. DelegatingFilterProxy 는 클라이언트의 요청을 Spring Security Filters 에 위임하는 역할을 한다. Proxy 가 붙은 이유로는 DelegatingFilterProxy 가 실제 필터 역할을 하는 Spring Security Filters 에 처리를 위임하는 대리인이기 때문인 것 같다.

DelegatingFilterProxy 는 결국 서블릿 컨테이너Spring Security Filter 를 호출할 수 있도록 하는 가교 역할을 하는 것이다. DelegatingFilterProxy서블릿 필터 자리에 위치하고 있다는 점에서 서블릿 컨테이너가 가 관리하는 대상이고, Bean 이 아니다. Spring Security FiltersApplicationContext 에서 관리되는 Bean 이다. [ 그림 2 ] 를 보면, DelegatingFilterProxyBean Filter 0 라고 표기된 것을 볼 수 있다.

코드를 통해 위에서 정리한 관계, 내용을 다시 한 번 확인해보자.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// Lazily get Filter that was registered as a Spring Bean
	// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
	Filter delegate = getFilterBean(someBeanName);
	// delegate work to the Spring Bean
	delegate.doFilter(request, response);
}

doFilter()DelegatingFilterProxy 가 클라이언트 요청을 받고, 이 요청을 처리할 Spring Security Filters 를 호출할 때 사용된다. ApplicationContext 에서 getFilterBean() 을 통해 Bean Filter 를 받아오는 것을 확인할 수 있다.

DelegatingFilterProxy클라이언트의 요청을 Spring Security Filters에 위임시키고, Spring Security Filters의 대리 역할을 한다고 정리할 수 있다.


| FilterChainProxy

image [ 그림 3 ].

[ 그림 2 ] 과 [ 그림 3 ] 을 비교하면, DelegatingFilterProxy 내부에 Bean FilterFilterChainProxy 로 변경된 것을 알 수 있다. 그리고 FilterChainProxySecurityFilterChain 을 바라보고 있다.

먼저, 앞서 접근한 것처럼 FilterChainProxy 이름을 분석해보자. Proxy 가 붙어 있는 것으로 봤을 때 FilterChain 을 대리하는 역할을 갖고 있는 것 같다.

그렇다면, FilterChain 가 무엇인 지 알아야겠다. 앞서 서블릿 필터 리뷰 할 때 서블릿 컨테이너FilterChain 을 갖고 있는 것을 봤었다. Spring Security Filter 역시 여러 개의 필터가 조합되어 체인 형태를 갖고 있고 이를 SecurityFilterChain 이라고 부른다. 그리고 SecurityFilterChain 내부에 [ 그림 2 ] 에서 봤던 Bean Filter 가 들어 있는 구조다.

FilterChainProxySpring Security 에서 제공하는 필터로 클라이언트 요청을 SecurityFilterChain 에 포함되어 있는 여러 필터에 위임시키는 역할을 담당한다.

그러면, 앞서 언급한 DelegatingFilterProxy 역할과 중복되지 않을까?

[ 그림 3 ] 을 보면, DelegatingFilterProxy 에 의해 감싸져 있는 형태로 되어 있다. DelegatingFilterProxy 가 서블릿 컨테이너에 의해 서블릿 필터로 등록되고, 이 필터에서 클라이언트 요청을 인터셉트한 뒤 BeanFilterChainProxy 에 요청을 위힘한다. 그리고, 이 요청을 받아서 실제 처리FilterChainProxySecurityFilterChain 에 포함된 Bean Filter 들을 순차적으로 호출하는 역할을 한다.


| SecurityFilterChain

image [ 그림 4 ]

[ 그림 4 ] 를 보면, 앞서 언급한 것 처럼 SecurityFilterChainBean Filter 를 포함한 것을 볼 수 있다. Security Filters 에서 Spring Security 에서 제공하는 필터 리스트를 확인할 수 있다.

image [ 그림 5 ]

서블릿 컨테이너 에서 필터체인 에 포함된 서블릿 필터 를 호출 할 때 기준으로 URL 을 활용한다. 각 요청에 따라서 필요한 필터만 적용하기 위해서다. Spring Security 에서도 URL 을 기준으로 적용될 필터를 구분할 수 있다. [ 그림 5 ] 에서 볼 수 있듯이 /api/** , /** 기준으로 적용될 필터 리스트를 갖고 있는 SecurityFilterChain 을 구분할 수 있고, 자세히 보면 [ 그림 5 ] 에서 각 SecurityFilterChain 에 포함된 Bean Filter 개수가 다른 것을 알 수 있다. 즉, 요청 별로 적용할 필터를 다르게 적용할 수 있는 형태인 것이다.

SecurityFilterChain 가 여러 개 존재할 때, URL 기준에 맞는 것 중 가장 앞에 있는 SecurityFilterChain 만 호출된다. 예를 들어서, /api/posts 요청이 왔을 때 [ 그림 5 ] 에서 두 개의 SecurityFilterChain 이 기준에 충족되지만, 순서 상 가장 앞에 있는 /api/** 에 해당되는 SecurityFilterChain 0 만 호출된다. 참고로, [ 그림 5 ] 에는 표현되지 않았지만, 0개의 Bean Filter 를 가질 수도 있다.


서두에 언급한 것 처럼 Architecture :: Spring Security 에서 제외된 내용은 별도의 토픽으로 다룰 예정이다. 직역 + 작성자 해석이 포함된 글이라서 잘 못된 내용이 있을 수 있고, 이에 대한 피드백은 언제나 환영한다.


Reference

Architecture :: Spring Security

Topical Guide | Spring Security Architecture

Servlet Filters and Event Listeners

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment