
- WAS의 필터에 하나의 필터를 만들어서 넣고 해당 필터에서 요청을 가로챈다
- 해당 요청은 스프링 컨테이너 내부에 구현되어 있는 스프링 시큐리티 감시 로직을 거친다
- 시큐리티 로직을 마친 후 다시 WAS의 다음 필터로 복귀한다


스프링 시큐리티 로직은 여러 개의 필터들이 나열된 필터 체인 형태로 구성되어 있다.

또한 여러 개의 필터 채인을 가질 수 있다.

- DelegatingFilterProxy: 스프링 Bean을 찾아 요청을 넘겨주는 서블릿 필터
- FilterChainProxy: 스프링 시큐리티 의존성을 추가하면 DelegatingFilterProxy에 의해 호출되는 SecurityFilterChain들을 들고 있는 Bean
- SecurityFilterChain: 스프링 시큐리티 필터들의 묶음으로 실제 시큐리티 로직이 처리되는 부분. FilterChainProxy가 SecurityFilterChain들을 들고 있다.
스프링 시큐리티 의존성을 추가하면 기본적인 DefaultSecutiryFilterChain 하나가 등록된다.
내가 원하는 SecutiryFilterChain을 등록하기 위해서는 SecurityFilterChain을 리턴하는 @Bean 메서드를 등록하면 된다.
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
...
@Bean
public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
...
return http.build();
}
// 복수 등록 시
@Bean
public SecutrityFilterChain filterChain2(HttpSecutiry http) throws Exception {
...
return http.build();
}
}
멀티 SecutiryFilterChain을 설정 시 N개의 SecurityFilterChain이 모두 "/**" 경로에서 매핑된다.
만약 직접 설정해주지 않으면 첫번째에서 전부 걸리게 된다.
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/signup").permitAll()
.anyRequest().permitAll());
위 코드 부분과는 관련이 없다. 만약 설정해주지 않고 다른 filter chain에 있는 url로 요청을 보내게 되면 찾지 못하는 상황이 발생한다.
@Bean
@Order(1)
public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
http
.securityMatchers((auth) -> auth.requestMatchers("/user"));
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/user").permitAll());
return http.build();
}
때문에 각 filter chain마다 위의 코드를 바탕으로 직접 url 매핑을 시켜주어야 한다.
또한, Order 어노테이션을 활용하면 filter chain의 등록 순서를 설정해줄 수 있다.
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring().requestMatchers("/img/**");
}
SecutiryFilterChain을 거치게 된다면 내부적으로 여러 가지 필터를 거치게 된다. 이때 서버의 자원을 사용하고 상주 시간이 발생하기 때문에 원하는 값을 필터를 통과하지 못하도록 설정할 수 있다.
보통 정적 자원의 경우 필터를 통과하지 않도록 위처럼 설정할 수 있다.
설정 시 하나의 SecutiryFilterChain이 0번 인덱스로 설정되며 해당 필터 채인 내부에는 필터가 없는 상태로 생성된다.
SecutiryFilterChain은 스프링 시큐리티의 보안, 인증/인가와 같은 주요 로직을 담당한다.
하나의 SecutiryFilterChain 내부에 N개의 필터를 구성하여 각각의 필터가 하나의 로직 수행의 시작점이 된다.

SecurityFilterChain 내부에 존재하는 각각의 필터가 시큐리티 관련 작업을 진행한다.
모든 작업은 기능 단위로 분업하여 진행함으로 앞에서 한 작업을 뒤 필터가 알기 위한 저장소 개념이 필요하다.

해당하는 정보는 Authentication이라는 객체에 담긴다.
다수의 사용자인 멀티 쓰레드 환경에서 SecurityContextHolder를 통해 SecurityContext를 부여하는 관리 전략은 다른 클래스에게 위임하는 것이다.
즉, SecutiryContextHolder는 SecurityContext들을 관리하는 메소드를 제공하지만 실제로 등록, 초기화, 읽기와 같은 작업은 SecurityContextHolderStrategy 인터페이스를 활용한다.
톰캣 WAS는 멀티 쓰레드 방식으로 동작한다. 유저가 접속하면 유저에게 하나의 쓰레드를 할당한다. 각각의 유저는 동시에 시큐리티 로그인 로직을 사용할 수 있다. 이때 SecutiryContextHolder의 필드에 선언된 SecurityContext를 호출하게 된다면 쓰레드간 공유하는 메모리의 code 영역에 데이터가 있기 때문에 정보가 덮어지는 현상이 발생한다고 생각할 수 있는데, threadLocal로 관리되기 때문에 쓰레드별 다른 구획을 나눠 제공한다.
Authentication 객체를 관리하는 SecurityContext는 사용자의 요청이 서버로 들어오면 생성되고, 처리가 끝난 후 응답되는 순간에 초기화된다.

GenericFilterBean은 내부적으로 동일한 필터를 여러 번 통과하더라도 통과한 수 만큼 내부 로직이 실행된다.
OncePerRequestFilter는 내부적으로 동일한 필터를 여러 번 통과하더라도 처음 한 번만 내부 로직이 실행된다.