Filter
Filter란 Web Application에서 관리되는 영역으로써 Srping Boot Framework에서 Client로부터 오는 요청/응답에 대해서 최초/최종 단계의 위치에 존재하며, 이를 통해서 요청/응답의 정보를 변경하거나, Srping에 의해서 데이터가 변환되기 전의 순수한 Client의 요청/응답 값을 확인할 수 있습니다.
유일하게 ServletRequest, ServletResponse의 객체를 변환할 수 있습니다.
주로 Spring Framework에서는 request/response의 Logging 용도로 활용하거나, 인증과 관련된 Logis들을 해당 Filter에서 처리합니다.
이를 선/후 처리함으로써, Service business logic과 분리시킵니다.
Client에서 요청을 하면 다음과 같은 순서로 실행됩니다.
Filter -> dispatcherservlet -> Interceptor -> AOP -> Controller
@ServletComponentScan
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class FilterApplication {
public static void main(String[] args) {
SpringApplication.run(FilterApplication.class, args);
}
}
필터를 사용하기 위해 반드시 어플리케이션 클래스에 @ServletComponentScan 어노테이션을 붙여줍니다!!!
@ServletComponentScan 어노테이션spring-boot 내장 웹서버를 사용할 경우 서블릿 Component(@WebFilter,@WebServlet, @WebListener)를 스캔할 때 사용하는 어노테이션입니다.
Filter 구현 예제
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/api/user/*")
public class GlobalFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 전처리
ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
String url = httpServletRequest.getRequestURI();
chain.doFilter(httpServletRequest, httpServletResponse);
// 후처리
String reqContent = new String(httpServletRequest.getContentAsByteArray());
log.info("response url : {}, request body : {}", url, reqContent);
String resContent = new String(httpServletResponse.getContentAsByteArray());
int httpStatus = httpServletResponse.getStatus();
// httpServletResponse.getContentAsByteArray() 메소드 실행 시 toByteArray 메소드가 실행되어서 response body의 내용을 삭제합니다.
// 그래서 바디의 내용을 다시 채워야합니다.
httpServletResponse.copyBodyToResponse();
log.info("response status : {}, responseBody : {}", httpStatus, resContent);
}
}
chain.doFilter에 client에서 받은 request와 response를 넘겨주어야 controller에서 request와 response을 받을 수 있습니다.
이 때, 그냥 client에서 받은 request와 response를 넘기면 "getReader() has already been called for this request" 에러 가 납니다.
그 이유는 이미 filter에서 request와 response 한번 읽었기 때문에 controller에서 읽으면 에러가 나는 것입니다.
그렇기에 ContentCachingRequestWrapper, ContentCachingResponseWrapper 인스턴스로 controller에 request와 response를 넘겨야합니다.
client에서 받은 request와 response 값을 수정하는 것은 조금 어려웠습니다.
get으로 받은 값들을 ContentCachingRequestWrapper.getParameter() 메소드를 이용해서 파라미터를 santize 하는 과정을 거쳐서 수정이 가능합니다.
반면 post는.... 제 능력으로는 부족했습니다 ㅠㅠ
혹시나 filter request body를 수정하는 방법을 아신다면, 공유부탁 드립니다.
우선 get으로 요청받은 값은 다음과 같은 클래스를 만들어서 수정하시면 됩니다.
package com.example.filter.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@Slf4j
public class FilteredRequest extends HttpServletRequestWrapper {
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public FilteredRequest(HttpServletRequest request) {
super(request);
}
public FilteredRequest(HttpServletRequest request, String param) {
super(request);
}
public String[] getParameterValues(String parameter) {
String values[] = super.getParameterValues(parameter);
if (values == null)
return null;
for (int i = 0; i < values.length; i++)
if (values[i] != null) {
StringBuffer strBuff = new StringBuffer();
for (int j = 0; j < values[i].length(); j++) {
char c = values[i].charAt(j);
switch (c) {
case 60: // '<'
strBuff.append("<");
break;
case 62: // '>'
strBuff.append(">");
break;
case 38: // '&'
strBuff.append("&");
break;
case 34: // '"'
strBuff.append(""");
break;
case 39: // '\''
strBuff.append("'");
break;
default:
strBuff.append(c);
break;
}
}
values[i] = strBuff.toString();
} else {
values[i] = null;
}
return values;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null)
return null;
StringBuffer strBuff = new StringBuffer();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
switch (c) {
case 60: // '<'
strBuff.append("<");
break;
case 62: // '>'
strBuff.append(">");
break;
case 38: // '&'
strBuff.append("&");
break;
case 34: // '"'
strBuff.append(""");
break;
case 39: // '\''
strBuff.append("'");
break;
default:
strBuff.append(c);
break;
}
}
value = strBuff.toString();
return value;
}
}
FilteredRequest filteredRequest = new FilteredRequest(httpServletRequest);
filteredRequest.getParameter("paramName");
// 이후 FilteredRequest 클래스 생성자에서 FilteredRequest.getParameter() 메소드를 호출하여 파라미터를 수정하는 방식으로 구현하면 될것 같습니다.
chain.doFilter(filteredRequest , httpServletResponse);
이상으로 부족한 filter 파트였습니다 ㅜㅜㅠ
참고로 inputStream을 String으로 변환할 수 있는 라이브러리를 소개합니다.
IOUtil 이라고 한번 사용해보시면 좋을 거 같습니다.
gradle 의존성
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
함께 보기 추천 CROS 에러에 관한 filter 설정
https://getthismoment.tistory.com/111
https://jronin.tistory.com/124
[Spring boot] Filter 설정
spring boot 학습 & 세팅 3탄 (2.3.9 RELEASE docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/html/) 1. @Component 또는 @ServletComponentScan WebFilter) 임베디드 WAS의 경우, 자동 설정에 의해..
jronin.tistory.com
https://whitecold89.tistory.com/40
[JAVA]Filter를 이용한 request 파라미터 변경 방법
Filter를 이용한 request 파라미터 변경 방법 Filter를 이용한 request 파라미터 변경 방법. package keis.user.comm; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterCha..
whitecold89.tistory.com
[java] 서블릿 필터로 요청 매개 변수 수정 - 리뷰나라
기존 웹 애플리케이션이 Tomcat 4.1에서 실행 중입니다. 페이지에 XSS 문제가 있지만 소스를 수정할 수 없습니다. 페이지에서보기 전에 매개 변수를 삭제하기 위해 서블릿 필터를 작성하기로 결정
daplus.net
'Spring Boot' 카테고리의 다른 글
Spring Boot - Interceptor (0) | 2021.09.23 |
---|---|
Spring Boot - Exception 구현 예제 (0) | 2021.09.13 |
Spring Boot - Exception 개괄 (0) | 2021.09.10 |
Spring Boot - Validation (0) | 2021.09.09 |
Spring Boot - Annotation 참고자료 (0) | 2021.09.07 |
댓글