WAS에서 톰캣이 올라가서 WAS에서 실행되는 필터이다.
요청을 받아서 Servlet에 전달하고, Servlet에서 응답을 받아서 클라언트에 전달하는 역할을 수행한다.
Servlet Container에서 생성되고 실행이 된다.
Servlet Filter는 스프링에서 정의된 빈을 주입해서 사용할 수 없다.
-> 서로 실행되는 컨테이너가 다르기 때문
인증/인가 처리는 스프링 컨테이너에 생성된 Filter를 통해서 처리된다.
실질적인 서블릿 필터가 DelegatingFilterProxy이다.
// web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
서블릿 컨테이너와 스프링 컨테이너(어플리케이션 컨텍스트) 사이의 링크를 제공하는 ServletFilter이다.
특정한 이름을 가진 스프링 빈을 찾아 그 빈에게 요청을 위임한다.
-> 서블릿 필터(서블릿 컨테이너)와 시큐리티 필터(스프링 컨테이너)는 서로 다른 컨테이너에서 생성되고 동작한다.
요청 순서
- Servlet Filter가 요청을 DelegatingFilterProxy로 전달한다.
// SecurityFilterAutoConfiguration
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties){
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
// DelegatingFilterProxyRegistrationBean
@Override
public DelegatingFilterProxy getFilter(){
return new DelegatingFilterProxy(this.targetBeanName, getWebApplicationContext()){
@Override
protected void initFilterBean() throws ServletException{
// Don't initialize filter bean on init()
}
};
}
// DelegatingFilterProxy
public DelegatingFilterProxy(String targetBeanName, @Nullable WebApplicationContext wac){
Assert.hasText(targetBeanName, "Target Filter bean name must not be null or empty");
this.setTargetBeanName(targetBeanName);
this.webApplicationContext = wac;
if (wac != null){
this.setEnvironment(wac.getEnvironment());
}
}
// DelegatingFilterProxy
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletExcpetion, IOException{
// Lazily nitialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null){
synchronized (this.delegateMonitor){
delegateToUse = this.delegate;
if (delegateToUse == null){
WebApplicationContext wac = findWebApplicationContext();
if (wac == null){
throw new IllegalStateException("No WebApplicationContext found: " + "no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
// Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
// FilterChainProxy
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if(clearContext){
try{
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
finally{
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}else{
doFilterInternal(request, response, chain);
}
}
/**
Creates the Spring Security Filter Chain
@return the {@link Filter} that represents the security filter chain
@throws Exception
*/
@Bean(name = AbstractSecurityWebApplicationInitailizer.DEFAULT_fILTER_NAME)
public Filter springSecurityFilterChain() throws Exception{
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
if(!hasConfigurers){
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter(){});
webSecurity.apply(adapter);
}
return webSecurity.build();
}