Spring Security 는 Security Filter Chain 을 사용하여
Client 의 요청을 Controller 로 오기전에 인증/인가 작업을 수행한다.
자주 사용하는 Spring Security 인 만큼 한번 더
간략하게 알아보는 것도 나쁘지 않다고 생각했다.
Servlet Filter는 J2EE 스펙에 기술된 기능으로, HTTP 요청이 서블릿에 도달하기 전에 요청을 가로채고 조작할 수 있게 해준다.
Servlet Filter를 사용하면 다음과 같은 작업을 수행하는데 좋다.
1.요청 변경
2.응답 수정
3. 요청 로깅
여러 개의 필터를 체인 형태로 연결할 수 있으며, 각 필터는 다음 필터로 요청을 전달한다. ( Filter Chain ) 자바 표준 스펙에 기재되어 있기 때문에, 자바 기반의 애플리케이션에서 모두 사용할 수 있다.
Spring Container 에서 관리되는 것이 아닌 Servlet Container 에서 관리가 된다. Spring Security 같이 Spring Container 에서 관리하는
필터는 관리하지 않는다.
Spring Security에서 인증 및 인가를 구현할 때 역시 필터를 사용한다. 여기서 Spring Security의 필터는 Spring Container에 속해 있을 텐데, 어떻게 Servlet Filter처럼 사용될 수 있는지 생각해봐야 한다.
DelegatingFilterProxy
Spring provides a
Filter
implementation namedDelegatingFilterProxy
that allows bridging between the Servlet container’s lifecycle and Spring’sApplicationContext
. The Servlet container allows registeringFilter
instances by using its own standards, but it is not aware of Spring-defined Beans. You can registerDelegatingFilterProxy
through the standard Servlet container mechanisms but delegate all the work to a Spring Bean that implementsFilter
.
Here is a picture of howDelegatingFilterProxy
fits into theFilter
instances and theFilterChain
.
"Delegating"은 위임한다는 말이다.
즉, Spring의 DelegatingFilterProxy는 서블릿 필터의 구현 권한을
Spring Bean에게 위임하여, Spring Bean으로 정의된 필터를
사용할 수 있게 해준다. 이를 통해 서블릿 컨테이너에서도 Spring Bean으로 관리되는 필터를 적용할 수 있게 된다.
SecurityFilterAutoConfiguration
클래스는 application 이 실행되고DelegatingFilterProxy
에 등록할 빈을 생성한다.
DelegatingFilterProxy
는springSecurityFilterChain
이라는 이름의 Bean 을 위임 받는다.
이때 위임 받는 Bean 은FilterChaingProxy
이다.
springSecurityFilterChain
으로 등록된 FilterChainProxy
가 실행
bean 이름이 'springSecurityFilterChain'임을 확인할 수 있다.
FilterChainProxy
에서 Bean에 등록된 필터를 가져와 등록한다.
( 추가된 Spring Security Filter 들을 볼 수 있다. )
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (!clearContext) {
doFilterInternal(request, response, chain);
return;
}
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
catch (Exception ex) {
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
Throwable requestRejectedException = this.throwableAnalyzer
.getFirstThrowableOfType(RequestRejectedException.class, causeChain);
if (!(requestRejectedException instanceof RequestRejectedException)) {
throw ex;
}
this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response,
(RequestRejectedException) requestRejectedException);
}
finally {
this.securityContextHolderStrategy.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
Servlet Filter를 사용하면 HTTP 요청을 가로채서 조작할 수 있습니다. 이 Filter들은 Servlet Container에서 관리된다.
Spring Framework에서는 Spring Container에서 관리되는 Bean들을 Servlet Container의 Filter로 사용하기 위해 DelegatingFilterProxy라는 특별한 필터를 제공한다.
DelegatingFilterProxy는 Spring Bean으로 정의된 Filter를 Servlet Filter로 사용할 수 있게 해준다. 즉, Servlet Container에서도 Spring Container에서 관리되는 Filter들을 사용할 수 있도록 권한을 위임받는 역할을 합니다.
따라서, DelegatingFilterProxy를 사용하면 Spring Bean으로 정의된 Filter를 Servlet Container에서 사용할 수 있어서 편리하게 Spring의 IoC 기능을 활용할 수 있게 된다.