-
SpringSecurity1 - Spring Security Filter가 실행 되는 방법(feat. DelegatingFilterProxy)
2022. 7. 4.
clients가 보낸 requet가 servlet에 도착하기 전에 Spring Security Filter가 어떻게 실행될까?
아래는 SpringSecurity의 문서에 있는 사진을 사용했다.
위의 사진을 보면 DelegatingFilterProxy가 Spring Security Filter를 실행시키는 것처럼 보이는데 사진이 의미하는 바가 무엇일까?
SpringSecurity는 이름에서 부터 Spring IOC Container에서 생성된 Filter을 사용하지만 Clients의 요청은 Servlet으로 들어온다. 이것이 왜 문제가 되느냐. Servlet은 Servlet Filter를 기반으로 하는데 Servlet Filter는 Servlet 스펙이기 때문에 스프링에서 정의 된 빈을 주입받아 사용할 수 없다.
하지만 위의 사진에서 보이는 것처럼 DelegatingFiterProxy의 내부에 FilterChainProxy라는 위임 대상을 가지고 있는데 FilterChainProxy는 SpringSecurity에서 제공되는 특수 필터로 SpringSecurityFilterChain이라는 이름 가진 Bean을 호출하여 SercurityFilter를 수행하게 된다.
결국 DelegatingFiterProxy은 Servlet Container와 Spring의 IOC Container를 연결해주는 다리 역활을 하는 필터인 셈이다.
위의 그림에 보이는 FilterChain은 ApplicationFilterChain으로 등록된 filter를 순회하며 filter를 순서대로 실행 시키는데 아래를 보면 DelegatingFilterProxy도 그중 하나인것을 알 수 있다.
아래의 코드를 보면 DeleagtingFilterProxy는 FilterChainProxy을 호출하게 되고 FilterChainProxy의 BeanName은 “springSecurityFilterChain”이다.
그러면 누가 DeleagtingFilterProxy를 만들어주고 springSecurityFilterChain을 넣어주는 걸까
아래의 ApplicationFilter에서 internalDoFilter 메서드에 브레이크 포인트를 걸어서 확인해보았다.
3번째에서 DelegatingFilterProxyRegistrationBean이라는 class를 확인 할 수 있다. 여기로 가보자
DelegatingFilterProxyRegistrationBean 클래스에서는 getFilter() 메서드로 DelegatingFilterProxy를 생성했고, 여기에 this.targetBeanName이 왠지 springSecurityFilterChain이라는 BeanName을 볼 수 있을 것 같았다.
DelegatingFilterProxyRegistrationBean 를 생성하는 SecuriyFilterAutoConfiguration을 지나서..
AbstractSecurityWebApplicationInitializer 에서 springSecurityFilterChain이라는 BeanName을 확인 할 수 있었다.
정리하자면 SecuriyFilterAutoConfiguration에서 DelegatingFilterProxyRegistrationBean 빈을 만들고 여기서 DeleagtingFilterProxy라는 filter를 만들어 주는 것이다. 그리고 추가적으로 SecuriyFilterAutoConfiguration에서 DeleagtingFilterProxy필터를 등록을 하는 것을 볼 수 있었고, SecuriyFilterAutoConfiguration에서 볼것이 많이보이는데 나중에 조금 더 정리를 해보도록 하겠다.
아래는 SpringSecurity Arcitecture 부분을 번역 한 것인데 아주 깔끔하게 번역이 되지는 않았지만 구글 번역보다는 좀 나은거 같아서 공유했다. 문서를 바탕으로 위의 내용을 정리했기 때문에 크게 임팩트 있는 내용은 없지만 springSecurityFilterChain에서 수행하는 Filter의 종류도 볼겸 가벼운 마음으로 읽어보기 좋다.
Spring Security Architecture
Filter
Spring Security의 Servlet은 Servlet Filter를 기반으로 합니다. 그렇기 때문에, 필터의 역할을 보는 것이 먼저입니다. 아래의 그림은 단일 HTTP request가 들어왔을때의 계층화를 보여줍니다.
클라이언트는 애플리케이션에 요청을 보내고 컨테이너는 요청 URI 경로를 기반으로 HttpServletRequest를 처리해야하는 필터와 서블릿을 포함하는 FilterChain을 생성합니다.
Spring MVC 애플리케이션에서 Servlet은 DispatcherServlet의 인스턴스 입니다. 하나의 Servlet은 단일 HttpServletRequest와 HttpServletResponse를 처리 할 수 있습니다. 두개 이상의 필터를 이용했을때 : 하위 필터 및 서블릿이 호출되지 않도록 하고 이 경우에는 HttpServletResponese를 Filter에서 작성합니다. 그리고 하위 Servlet이나 Filter 가 사용할 HttpServletRequest 또는 HttpServletResponse 을 수정할 수 있습니다. Filter 의 힘은 FilterChain 을 통과할때 발생합니다.
DelegatingFilterProxy
Spring은 Servlet Container의 라이프 사이클과 스프링의 ApplicationContext 사이의 브릿징 역활을 하는 DelegatingFilterProxy라는 필터 구현을 제공 합니다. Servlet Container는 자체 표준을 사용하여 필터를 등록할 수 있지만 Spring Bean에서 인식 하지 못합니다. DelegatingFilterProxy는 표준 서블릿 컨테이너 메커니즘을 통해 등록할 수 있지만 Spring Bean에 등록된 filter에게 모든 일을 위임 해야합니다.
DelegatingFilterProxy는 AppplicationContext에서 Bean Filter을 찾아서 호출을 합니다.
DelegatingFilterProxy의 다른 이점은 Filter Bean 인스턴스를 찾는 것을 지연시킬 수 있다는 것입니다. 컨테이너가 시작되기 전에 컨테이너가 필터 인스턴스를 등록해야 하기때문에 이 이점은 중요할 수 있습니다. 하지만 Spring은 일반적으로 Filter 인스턴스가 등록 될때까지 실행되지 않는 Spring Bean을 로드하기 위해 ContextLoaderListener를 사용한다.
FilterChainProxy
Spring Security 의 서블릿은 FilterChainProxy 안에 포함되어 지원됩니다. FilterChainProxy 은 SecurityFilterChain를 통해 많은 Filter 인스턴스에 위임할 수 있도록 하는 Spring Security에서 제공되는 특수 Filter입니다. FilterChainProxy 은 Bean이므로 일반적으로 DelegatingFiterProxy에 wrapped 되어 있습니다.
SecurityFilterChain
SecurityFilterChain은 FilterChainProxy에서 이 요청에 대해 호출해야 하는 Spring 보안 필터를 결정하는데 사용됩니다.
SecurityFilterChain 안에 있는 Security Filter은 일반적으로 Bean입니다. 하지만 DelegatingFilterProxy대신 FilterChainProxy에 등록됩니다. FilterChainProxy는 Servlet 컨테이너 또는 DelegatingFilterProxy에 직접 등록할 때 많은 이점을 제공합니다. 첫번째 Spring Security의 모든 Servlet 지원을 위한 시작점을 제공합니다. 그런 이유로 Spring Security의 Servlet 지원 문제를 해결하려는 경우 FilterChainProxy에 디버그 지점을 추가하는 것이 시작하기에 좋은 장소입니다. 둘째, FilterChainProxy는 Spring Security 사용의 핵심이기 때문에 선택 사항으로 보이지 않는 작업을 수행할 수 있습니다. 예를 들어 메모리 누수를 피하기 위해 SecurityContext를 지웁니다. 또한 Spring Security의 HttpFirewall을 적용하여 특정 유형의 공격으로부터 애플리케이션을 보호합니다. 또한 SecurityFilterChain을 호출해야 하는 시기를 결정할 때 더 많은 유연성을 제공합니다. 서블릿 컨테이너에서 필터는 URL만을 기반으로 호출됩니다. 그러나 FilterChainProxy는 RequestMatcher 인터페이스를 활용하여 HttpServletRequest의 모든 항목을 기반으로 호출을 결정할 수 있습니다. 실제로 FilterChainProxy를 사용하여 어떤 SecurityFilterChain을 사용해야 하는지 결정할 수 있습니다. 이를 통해 애플리케이션의 여러 조각에 대해 완전히 별도의 구성을 제공할 수 있습니다.
다중 SecurityFilterChain 그림에서 FilterChainProxy는 어떤 SecurityFilterChain을 사용해야 하는지 결정합니다. 일치하는 첫 번째 SecurityFilterChain만 호출됩니다. /api/messages/의 URL이 요청되면 먼저 SecurityFilterChain(0)의 /api/** 패턴과 일치하므로 SecurityFilterChain(n)에서도 일치하더라도 SecurityFilterChain(0)만 호출됩니다. 다른 맞는 필터가 없다면 SecurityFilterChain(n)가 호출됩니다.
Security Filters
보안 필터는 SecurityFilterChain API를 사용하여 FilterChainProxy에 삽입됩니다. 필터의 순서가 중요합니다. 일반적으로 Spring Security의 필터 순서를 알 필요는 없습니다. 그러나 순서를 아는 것이 유익한 경우가 있습니다.
https://docs.spring.io/spring-security/reference/servlet/architecture.html#servlet-security-filters
'프레임워크 > Spring' 카테고리의 다른 글
@Valid를 이용해 타임리프에서 유효성 검증하기 (1) 2022.08.19 SpringSecurity2 - Authentication Architecture (0) 2022.07.13 HttpSession은 어떻게 만들어지고 어떻게 유지될까(feat. 코드를 통해 확인하는 JSESSION의 생성 방법과 기존 세션 확인 방법) (2) 2022.06.11 Exception (feat. @ControllerAdvice를 이용한 Exception 전역화) (0) 2022.06.06 @NoArgsConstructor(access = AccessLevel.PROTECTED)를 이용하여 의미있는 생성자를 만들어 보자( + @Bulider) (0) 2022.06.06 댓글