spring

Spring Filter

noAb 2024. 6. 1. 17:05

필터는 사용자의 요청이 컨틀로러의 들어오기전에 수문장 역할을 하여 구분을 할 수있게 해주는 역할을 합니다.

로그인이 되지 않은 사용자에게 회원정보화면을 들어가면 안되는 것처럼 회원정보 요청이 들어올때 로그인 여부를 필터에서 판별하여 로그인이 되어있지 않다면 로그인 페이지로 이동을 할 수있게 해줄수 있다.

 

필터 흐름

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러

위와같은 흐름 사이에 필터를 넣어주게 되면 필터는 체인처럼 여러 필터를 거칠수도 있다.


필터에 사용되는 메서드

@Slf4j
public class LoginFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("log filter inti");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
         String requestURI = httpRequest.getRequestURI();
         String uuid = UUID.randomUUID().toString();
         try {
             log.info("REQUEST  [{}][{}]", uuid, requestURI);
             filterChain.doFilter(request, response);
         } catch (Exception e) {
             throw e;
         } finally {
             log.info("RESPONSE [{}][{}]", uuid, requestURI);
        }
    }

    @Override
    public void destroy() {
        log.info("log filter destroy");
    }
}

기본적으로 필터로 사용하기 위해 Filter를 상속받은 클래스는 위의 3가지 메서드를 오버라이딩하게 된다.

  • init():` 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.
  • doFilter():` 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
  • destroy():` 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.

doFilter메서드가 메인이라고 할 수있는데 요청URI를 확인하면서 filterChain.doFilter를 호출하는데 다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출한다. 만약 이 로직을 호출하지 않으면 다음 단계로 진행되지 않는다.

이제 필터를 만들었다면 등록을 해야합니다.

 

FilterRegistrationBean

스프링 부트가 제공하는 필터 등록하는 방법

@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new
        FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(new LogFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    } 
}
  • setFilter(new LogFilter())` : 등록할 필터를 지정한다.
  • setOrder(1)` : 필터는 체인으로 동작한다. 따라서 순서가 필요하다. 낮을 수록 먼저 동작한다.
  • addUrlPatterns("/*")` : 필터를 적용할 URL 패턴을 지정한다. 한번에 여러 패턴을 지정할 수 있다.

이제 간단한 로그인 예시를 만들어보겠습니다.

@Slf4j
public class LoginCheckFilter implements Filter {

    private static final String[] whiteList = {"/","members/add","/login","/css/*"};
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String requestURI = httpServletRequest.getRequestURI();

        try{
            log.info("인증 체크 필터 시작{}",requestURI);
            if(isLoginCheckPath(requestURI)){
                log.info("인증체크 로직 실행 {}",requestURI);
                HttpSession session = httpServletRequest.getSession(false);
                if(session == null || session.getAttribute(SessionConst.LONG_MEMBER) == null){
                    log.info("미인증 사용자 요청 {}",requestURI);
                    httpServletResponse.sendRedirect("/login?redirectURL="+requestURI);
                    return;
                }
            }
            filterChain.doFilter(servletRequest,servletResponse);

        }catch (Exception e){
            throw e;
        }finally {
            log.info("인증 체크 필터 종료 {}",requestURI);
        }
    }

    /*
    *   화이트 리스틩 겨우 인증 체크X
    * */
    private boolean isLoginCheckPath(String requestURI){
        return !PatternMatchUtils.simpleMatch(whiteList,requestURI);
    }
}

위에 지정해놓은 whiteList에 등록된 url인경우 제외한 요청이 들어오면 세션을 체크하고 회원세션을 체크하여 로그인 페이지로 이동을 하게 되고 편한 이용을 위해 param으로 redirectURL을 담아서 이동을 하게 만들었습니다.

마지막으로 위와 같은 방법으로 필터를 등록하면 사용이 가능합니다.