# 필터 구현

* 요청을 수신하고 로직을 실행한 뒤 다음 체인의 필터에 요청을 위임한다.
* 인증을 보강하기 위해 OTP를 ㅊ ㅜ가하거나 로깅과 관련된 기능 등을 추가할 수 있다.

## 9.1. 스프링 시큐리티 아키텍처의 필터 구현

* Filter 인터페이스를 구현하고 doFilter() 메서드를 재정의한다.
  * ServletRequest
    * HTTP 요청을 나타낸다.
  * ServletResponse
    * HTTP 응답을 나타낸다.
  * FilterChain
    * 체인의 다음 필터로 요청을 전달한다.
    * 필터 체인: 작동 순서가 정의된 필터의 모음
* 기본적으로 구현된 필터
  * BasicAuthenticationFilter
    * HTTP Basic 인증을 처리한다.
    * httpBasic()을 호출하면 필터 체인에 추가된다.
  * CsrfFilter
    * 사이트 간 요청 위조를 처리한다.
  * CorsFilter
    * 교차 출처 리소스 공유 권한 부여 규칙을 처리한다.
* 여러 필터가 같은 위치에 있으면 호출되는 순서는 랜덤이다.

## 9.2. 체인에서 기존 필터 앞에 필터 추가

```java
public class RequestValidationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 로직 구현
    }
}

```

```java

@Configuration
public class ProjectConfig {

    ...

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(new RequestValidationFilter(), BasicAuthenticationFilter.class)
                .authorizeHttpRequests(requestMatcherRegistry -> requestMatcherRegistry.anyRequest().permitAll());

        return http.build();
    }
}

```

* 필터에 로직을 구현하고 체인에 추가한다.

## 9.3. 체인에서 기존 필터 뒤에 필터 추가

```java

@Configuration
public class ProjectConfig {

    ...

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(new RequestValidationFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(new AuthenticationLoggingFilter(), BasicAuthenticationFilter.class)
                .authorizeHttpRequests(requestMatcherRegistry -> requestMatcherRegistry.anyRequest().permitAll());

        return http.build();
    }
}

```

## 9.4. 필터 체인의 다른 필터 위치에 필터 추가

* 기존 필터에 다른 필터를 적용하면 대체되는 것이 아니라 순서를 보장하지 않는 상태에서 실행된다.
* 인증 키는 속성 파일이 아니라 비밀 볼트를 이용한다.

```java

@Configuration
public class ProjectConfig {

    ...

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(new RequestValidationFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(new AuthenticationLoggingFilter(), BasicAuthenticationFilter.class)
                .addFilterAt(new StaticKeyAuthenticationFilter(), BasicAuthenticationFilter.class)
                .authorizeHttpRequests(requestMatcherRegistry -> requestMatcherRegistry.anyRequest().permitAll());

        return http.build();
    }
}

```

```java
@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
```

* UserDetailsService가 필요하지 않다면 비활성화 할 수 있다.

## 9.5. 스프링 시큐리티가 제공하는 필터 구현

* GenericFilterBean
  * web.xml에 정의한 초기화 매개 변수를 이용할 수 있다.
* OncePerRequestFilter
  * GenericFilterBean을 확장한 더 유용한 클래스
  * doFilter()가 한 번만 실행되는 것을 보장한다.
  * HTTP 요청만 지원해서 request, response 값을 형변환 할 필요가 없다.
  * shouldNotFilter()로 적용되지 않는 경우를 재정의할 수 있다.
  * 비동기 요청이나 오류 발송 요청에는 적용되지 않는다.
    * 이떄는 shouldNotFilterAsyncDispatch(), shouldNotFilterErrorDispatch()를 재정의한다.
* 스프링이 제공하는 클래스를 굳이 쓸 필요 없는 간단한 사례라면 안 써도 된다.
