1. Filter
- 스프링 시큐리티는 Servlet Filter를 기반으로 서블릿을 지원한다
- Filter 는 HTTP 요청과 응답을 변경할 수 있는 재사용 가능한 코드이다
- 필터는 사용 여부를 지정할 수 있다
- spring 내부에 보유하고 있는 필터를 자동으로 사용할 수 있다
- spring 내부에 보유하고 있지만 자동으로 사용하지 않는 필터를 사용하돌록 설정할 수 있다
- spring 내부에 보유하고 있지 않은 필터를 지정하여 사용할 수 있다 - @을 사용하거나 .xml 을 사용하여 설정할 수 있다


2. FilterChain
- 여러개의 Filter가 사슬처럼 연결되어 상호 동작하는 것을 의미한다

- 클라이언트가 앱에 요청을 보내고 컨테이너는 요청 URI의 경로를 기반으로 필터와 서블릿을 적용할지 결정한다
- 하나의 서블릿은 단일 요청을 처리하지만, 필터는 체인을 형성하여 순서를 지정하며 실제로 요청 자체를 처리하려는 경우 필터가 나머지 체인을 거부 할 수 있다
- 필터는 다운스트림 필터와 서블릿을 사용해서 요청과 응답을 수정할 수도 있다
- 필터 체인의 순서는 매우 중요하며 Spring Boot는 두 가지 메커니즘을 통해 이를 관리한다
- Filter 타입의 @Beans에 @Order를 붙이거나 Orderd를 구현한다
- API의 일부로 순서를 가지는 FilterRegistrationBean의 일부가 된다 - 클라이언트는 애플리케이션으로 요청을 전송하고, 컨테이너는 Servlet과 여러 Filter로 구성된 FilterChain을 만들어 요청 URI path 기반으로 HttpServletRequest를 처리한다
- Filter는 요청이 DispatcherServlet에 의해 다뤄지기 전,후에 동작한다
- Filter는 FilterChain을 통해 여러 필터가 연쇄적으로(순서) 동작하게 할 수 있다
- 1개의 Servlet이 HttpServletRequest와 HttpServletResponse를 처리한다
- Filter는 여러 개를 사용할 수 있다
- 다운스트림의 Servlet과 Filter의 실행을 막는 경우에는 Filter에서 HttpServletResponse를 작성한다
- 다운스트림에 있는 Servlet과 여러 Filter로 HttpServletRequest나 HttpServletResponse를 수정한다 - Filter는 FilterChain 안에 있을 때 효력이 있다
3. Filter 인터페이스
- public void init(FilterConfig filterConfig) throws ServletException
- 필터를 웹 콘테이너 내에 생성한 후 초기화할 때 호출한다 - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException
- 체인을 따라 다음에 존재하는 필터로 이동한다
- 체인의 가장 마지막에는 클라이언트가 요청한 최종 resource가 위치한다 - public void destroy( )
- 필터가 웹 콘테이너에서 삭제될 때 호출된다 - 메소드에서 필터의 역할을 하는 메소드가 doFilter() 메소드이다
- 서블릿 콘테이너는 사용자가 특정 resource를 요청할 경우, resource 사이에 필터가 있으면 필터 객체의 doFilter() 메소드를 호출하며, 호출 시점부터 필터가 작용하기 시작한다
1) FilterChain에 사용되는 Filter 구현 코드
public class FirstFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
// 필터 초기화 작업
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// 1. request 파리미터를 이용하여 요청의 필터 작업 수행
// 2. 체인의 다음 필터 처리
chain.doFilter(request, response);
// 3. response를 이용하여 응답의 필터링 작업 수행
}
public void destroy() {
// 주로 필터가 사용한 자원을 반납
}
}
4. Filter 실습
1) 'Spring Security 환경구성 - https://coding-mid-life.tistory.com/71 '에서 작성한 프로젝트를 기본으로 한다
- Filter 패키지를 만들고 FirstFilter 클래스를 생성한다
- Filter 인터페이스를 FirstFilter로 구현한다
package com.memberlogin.loginjoin.filter;
import javax.servlet.*;
import java.io.IOException;
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("FirstFilter 생성됨");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("========First 필터 시작========");
chain.doFilter(request, response);
System.out.println("========First 필터 종료========");
}
@Override
public void destroy() {
System.out.println("FirstFilter 사라짐");
Filter.super.destroy();
}
}
- FirstFilter를 적용하기 위한 Config 파일을 작성한다
- 프로젝트를 재실행하면 init 메서드가 실행되면서 콘솔에 'FirstFilter 생성됨'이 출력된다
- Controller에 적용된 url로 접속하게 되면 doFilter → controller 동작 → destroy 메서드가 실행되면서 '========First 필터 시작========', '========First 필터 종료========'가 출력된다
package com.memberlogin.loginjoin.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegister() {
FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
return registrationBean;
}
}

- Filter를 적용시키기 위해 다양한 옵션(addUrlPatterns, setOrder 메서드)들이 있다
- registrationBean.addUrlPatterns(”/users/*”);
- registrationBean.setOrder(1);
- 2개 이상 필터를 적용하기 위하여 SeconfFilter 클래스를 생성한다
package com.memberlogin.loginjoin.filter;
import javax.servlet.*;
import java.io.IOException;
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("SecondFilter가 생성되었습니다.");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("==========Second 필터 시작==========");
chain.doFilter(request, response);
System.out.println("==========Second 필터 종료==========");
}
@Override
public void destroy() {
System.out.println("SecondFilter가 사라집니다.");
Filter.super.destroy();
}
}
- Config 클래스의 내용을 수정한다
- registrationBean.setOrder() 메서드를 통해 순서를 설정할 수 있다
@Configuration
public class Config {
@Bean
public FilterRegistrationBean<FirstFilter> firstFilterRegister() {
FilterRegistrationBean<FirstFilter> registrationBean = new FilterRegistrationBean<>(new FirstFilter());
//순서 설정 추가
registrationBean.setOrder(1);
return registrationBean;
}
//SecondFilter 설정 추가
@Bean
public FilterRegistrationBean<SecondFilter> secondFilterRegister() {
FilterRegistrationBean<SecondFilter> registrationBean = new FilterRegistrationBean<>(new SecondFilter());
registrationBean.setOrder(2);
return registrationBean;
}
}

- 아래는 재실행 후 콘솔에 출력되는 화면이다

- 애플리케이션에 접속하면 출력되는 콘솔 화면이다
- Filter는 다운스트림에 있는 나머지 Filter와 Servlet에만 영향을 주기 때문에 순서가 중요하다

5. DelegatingFilterProxy
- 스프링 시큐리티가 모든 애플리케이션의 요청에 보안이 적용되게 하는 서블릿필터이다
- 스프링 프레임워크 기반의 웹 애플리케이션에서 서블릿 필터 라이프 사이클과 연계해 스프링 빈 의존성을 서블릿 필터에 바인딩하는데 사용한다
- 스프링 부트는 DelegatingFilterProxy라는 Filter 구현체로 서블릿 컨테이너의 생명주기와 스프링 ApplicationContext를 연결한다
- 서블릿 컨테이너는 자체 표준을 사용해서 Filter를 등록할 수 있지만 스프링이 정의하는 Bean은 인식하지 못한다
- DelegatingFilterProxy는 표준 서블릿 컨테이너 메커니즘으로 등록할 수 있지만, 모든 처리를 Filter를 구현한 스프링 빈으로 위임해 준다

- DelegatingFilterProxy는 ApplicationContext에서 Bean Filter A를 찾아 실행한다
- Bean Filter A는 FilterChainProxy가 된다
6. FilterChainProxy
- 스프링 시큐리티는 FilterChainProxy 로 서블릿을 지원한다
- FilterChainProxy 는 스프링 시큐리티가 제공하는 특별한 Filter로 SecurityFilterChain을 통해 여러 Filter 인스턴스로 위임할 수 있다
- FilterChainProxy는 빈이기 때문에 보통 DelegatingFilterProxy로 감싸져 있다
- DelegatingFilterProxy는 서블릿 필터이며, Spring IOC 컨테이너가 관리하는 Filter Bean을 갖고 있다
- Filter Bean은 FilterChainProxy이며 객체안에서 Security와 관련된 일들이 진행된다

- 순수한 Servlet Filter는 본래 Spring Container 외부에 존재한다
- DelegatingFilterProxy 클래스는 Filter를 Spring Bean으로 사용할 수 있도록 한다
- DelegatingFilterProxy 클래스(Filter Class)는 Servlet Filter 사이에 존재하고 Spring Bean으로 등록된 Filter에게 처리를 위임한다
※ 참조 1

- FilterChain에서 여러 Filter를 적용할 수 있다
- Filter 실행 중에 DelegatingFilterProxy가 존재할 수 있다
- DelegatingFilterProxy 내부에 있는 Bean Filter는 FilterChainProxy가 된다 - SecurityFilterChain은 FilterChainProxy로 등록된다
- 여러 개의 SecurityFilterChain이 있을 때 어떤 것을 사용할지는 FilterChainProxy가 결정한다
- 가장 먼저 매칭한 SecurityFilterChain을 실행한다
- /api/message/ url 요청
: SecurityFilterChainn(/)도 일치하지만 SecurityFilterChain0(/api/) 패턴과 제일 먼저 매칭되므로 가장 먼저 매칭되는 SecurityFilterChain0만 실행한다
- /message/ url 요청
: 가지고 있는 SecurityFilterChain들을 시도해보지만 매칭되는 SecurityFilterChain 인스턴스가 없다면 SecurityFilterChainn(/)을 실행한다 - Proxy는 “우회” “대신” 등을 의미하고 소프트웨어 디자인 패턴에서의 프록시 패턴에서 사용하는 의미와 비슷하며 네트워크에서의 프록시 개념과도 일맥상통 한다
※ 참조 2
■ Spring Security Filter 종류
- Security Filter들은 항상 모든 Filter가 수행되지 않고 프로젝트 구성 및 설정에 따라 일부 Filter만 수행된다
- 직접적으로 개발자가 핸들링할 필요가 없다
- 예외적으로 개발자가 Custom Filter를 작성하고 등록할때 기존 필터들 사이에서 수행되어야 할 필요가 있는 경우가 있을때에 참고하여 적용한다
- 각 Filter의 호출 순서는 위에서부터 아래로 진행된다
ChannelProcessingFilter
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
OAuth2AuthorizationRequestRedirectFilter
Saml2WebSsoAuthenticationRequestFilter
X509AuthenticationFilter
AbstractPreAuthenticatedProcessingFilter
CasAuthenticationFilter
OAuth2LoginAuthenticationFilter
Saml2WebSsoAuthenticationFilter
UsernamePasswordAuthenticationFilter
OpenIDAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
ConcurrentSessionFilter
DigestAuthenticationFilter
BearerTokenAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
JaasApiIntegrationFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
SwitchUserFilter
'Spring Security' 카테고리의 다른 글
| Spring Security - OAuth2 인증 - 환경 설정 (0) | 2022.08.01 |
|---|---|
| Spring Security - OAuth2 인증(Authentication) (0) | 2022.07.31 |
| Spring Security - JWT 로그인 (0) | 2022.07.28 |
| Spring Security - JWT Bearer 인증 (0) | 2022.07.27 |
| Spring Security - JWT 인증(Authentication) (0) | 2022.07.27 |