• [2023.06.10 수정] Spring Filter 도입하기
    개발공부/Spring 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]

    반응형

    댓글

Designed by Tistory.