개발공부/Spring

[2023.06.10 수정] Spring Filter 도입하기

원석💎-dev 2022. 5. 15. 14:56
반응형

1. Filter와 OncePerRequestFilter의 차이

  •  Servlet은 사용자의 요청을 받으면, Servlet을 생성해 메모리에 저장해 두고, 같은 클라이언트의 요청을 받으면 생성해둔 Servlet객체를 재활용하여 요청을 처리한다.
  •  Spring (주로 Spring Security)에서는 RequestDispatcher 클래스를 이용해 사용자의 요청에 의해 생성된 Servlet에서 다른 Servlet으로 dispatch하는 경우가 있는데, 이때 Filter가 두번 실행된다.
  •  OncePerRequestFilter의 경우 사용자 요청 당 한 번의 Filter만 적용되는 것이 보장된다.

 

참고 글 :

Spring Security에서 사용되는 RequestDispatcher [https://dev-ppyong.tistory.com/12]

Filter와 OncePerRequestFilter의 차이 [https://minkukjo.github.io/framework/2020/12/18/Spring-142/]

RequestDispatcher와 HttpServletResponse#sendRedirect의 차이​ [https://dololak.tistory.com/502]

 

2. Requset Header, Body 내용 변경 및 추가하기

  • OncePerRequestFilter에서는 doFilterInternal() 함수를 이용해 servlet Request, Response Filter를 수행한다.
  • Filter를 사용하는 것은 Request 또는 Reponse의 값의 body나 header 값을 검증, 변경, 추가하는 목적이 있다. 하지만 HttpServletRequest 객체의 값은 직접 수정할 수 없어, HttpServletRequestWrapper, HttpServletResponseWrapper을 상속받아 직접 구현할 수 있다.
  • getHeader의 return이 not null이 되게 할 수 있지만, spring boot를 사용한다면 기본 필터가 적용되어 사용하지 않는 header를 호출할 수 있다. 그래서 getHeader를 사용할 때 null이 반환이 가능해야 오류가 발생하지 않는다.
  • header의 값의 직접 수정이나 추가를 지양하자.
    • 함수로 받아온 변수를 직접 수정하는 일은 거의 없다. 헤더도 마찬가지로 클라이언트가 보내온 변수로 여기고 수정을 지양하자.
  • Requset Header에 값 추가하기 (Spring Boot, Kotlin)
class RequestHeaderWrapper(request: HttpServletRequest) : HttpServletRequestWrapper(request) {
    private val headerMap = mutableMapOf<String, String?>()

    fun addHeader(name: String, value: String?) { headerMap[name] = value }

    override fun getHeader(name: String): String? {
        var headerValue = super.getHeader(name)
        if (headerMap.containsKey(name)) {
            headerValue = headerMap[name]
        }
        return headerValue
    }

    override fun getHeaderNames(): Enumeration<String> {
        val names: List<String> = Collections.list(super.getHeaderNames()).apply {
            headerMap.forEach { name -> this.add(name.key) }
        }.distinct()

        return Collections.enumeration(names)
    }

    override fun getHeaders(name: String): Enumeration<String?> {
        val values: List<String?> = Collections.list(super.getHeaders(name)).apply {
            if (headerMap.containsKey(name)) {
                this.add(headerMap[name])
            }
        }

        return Collections.enumeration(values)
    }
}
override fun doFilterInternal(
   request: HttpServletRequest,
   response: HttpServletResponse,
   filterChain: FilterChain
) {
   val accessToken = "testAccessToken"
   val requestWrapper = if (accessToken.isNullOrEmpty()) {
      request
   } else {
      val requestWrapper = RequestHeaderWrapper(request)
      requestWrapper.addHeader("X-Requester-Access-Token", accessToken)
      requestWrapper
   }

   filterChain.doFilter(requestWrapper, response)
}

참고 글 :

Requset Header 추가하기 [http://makble.com/adding-http-headers-to-requests-in-filters-and-servlets]

 

3. Filter chain의 순서 정하기 (+ Spring Security Filter)

  • FilterRegistrationBean에 순서(Order)설정 말고도 다양한 세팅을 해줄 수 있다.
@Configuration 
public class ServletConfig { 

   @Bean
   public firstFilter(): FilterRegistrationBean<FirstFilter> { 
      val registrationBean = FilterRegistrationBean(FirstFilter())
      registrationBean.setOrder(1); 
      return registrationBean; 
   } 
   
   @Bean 
   public firstFilter(): FilterRegistrationBean<SecondFilter>{ 
      val registrationBean = FilterRegistrationBean(SecondFilter())
      registrationBean.setOrder(2); 
      return registrationBean; 
   } 
 }
  • Spring Security를 사용할 경우 자동으로 제공해주는 Filter들이 존재한다.
  • Spring Secuirty가 제공하는 Filter 확인하기 위해 @EnableWebSecurity(debug = true)를 붙이고 실행하면, Security의 Filter목록이 log로 출력된다.
@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  ...
}

 

  • Spring Secuirty가 제공하는 Filter보다 사용자 정의 Filter를 먼저 사용하고 싶다면 application.yaml 파일에  spring.security.filter.order=10을 추가해준다. spring security Filter앞에 10개의 사용자 정의 Filter를 추가할 수 있다.

참고 글 :

FilterChain이란? [https://dololak.tistory.com/599]

Filter 순서 설정하기 [https://www.baeldung.com/spring-boot-add-filter]

Spring Security Filter chain 확인 [https://vsh123.github.io/spring%20security/Spring-Security-Filter-chain/]

Spring Security Filter 보다 사용자 정의 Filter 먼저 사용 [https://12teamtoday.tistory.com/141]

반응형