복습을 위한

서블릿 필터 본문

SpringMVC

서블릿 필터

ho042479 2024. 1. 31. 19:08

웹과 관련된 공통 관심사를 처리할 때 서블릿 필터를 사용한다. 

예를 들어 로그인을 한 사용자만이 특정페이지에 접근을 할 수 있어야한다를 만족시키고싶을 때같은 경우이다. 

 

필터 흐름 

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

 

필터를 적용하면 필터가 호출 된 다음에 서블릿이 호출된다. 그래서 모든 고객의 요청 로그를 남기는 요구사항이 있다면 필터를 사용하면 된다. 참고로 필터는 특정 URL 패턴에 적용할 수 있다. /* 이라고 하면 모든 요청에 필터가 적용된다. 참고로 스프링을 사용하는 경우 여기서 말하는 서블릿은 스프링의 디스패처 서블릿으로 생각하면 된다.

 

필터체인

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

 

필터는 체인으로 구성되는데, 중간에 필터를 자유롭게 추가할 수 있다. 예를 들어서 로그를 남기는 필터를 먼저 적용하 고, 그 다음에 로그인 여부를 체크하는 필터를 만들 수 있다

 

필터인터페이스
public interface Filter {
 public default void init(FilterConfig filterConfig) throws ServletException
{}
 public void doFilter(ServletRequest request, ServletResponse response,
 FilterChain chain) throws IOException, ServletException;
 public default void destroy() {}
}

init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.

doFilter(): 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.

destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.

default메소드가 있기 때문에 doFilter만 구현해도된다. 

 

 

 

로그인 인증체크 필터를 구현해보자

@Slf4j
    public class LoginCheckFilter implements Filter{

    //로그인하지않아도 허용되는 페이지들
    private static final String[] whitelist = {"/","/members/add", "/login","/logout","/css/*"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

        HttpServletResponse httpResponse =(HttpServletResponse) response;

        try{
            log.info("인증체크필터 시작{}", requestURI);
            if(isLoginCheckPath(requestURI)){
                log.info("인증체크 로직 실행{}",requestURI);
                HttpSession session = httpRequest.getSession(false);
                 if(session ==null || session.getAttribute(SessionConst.LOGIN_MEMBER)==null){
                     log.info("미인증 사용자 요청{}", requestURI );
                     //로그인창으로 redirect
                     httpResponse.sendRedirect("/login?redirectURL="+requestURI);
                     //로그인화면 보내고 로그인 성공하면 기존 화면으로 돌아올 수 있게 배려하기위해 일단 현재페이지URL도 loginController로 같이 넘겨주자
                     return;//인증안되면 다음 필터나 컨트롤러로 못넘어감. finally문 실행되고 메소드 종료
                 }
            }
                chain.doFilter(request, response);//(whitelist이면) false면 다음 필터로 가든가 아님 서블릿으로 넘어감
        }catch (Exception e){
            throw e;
        }finally {
            log.info("인증 체크 필터 종료 {}", requestURI);
        }

    }
    /*
    * 화이트 리스트의 경우 인증 체크하지않는 메소드*/
    private boolean isLoginCheckPath(String requestURI){
            return !PatternMatchUtils.simpleMatch(whitelist,requestURI);
    }//접근하는 사이트가 whitelist이면 false ,   whitelist가 아니면 필터체크해야하니 true반환
}

 

chain.doFilter(request, response); 이 부분이 가장 중요하다. 다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출한다. 만 약 이 로직을 호출하지 않으면 다음 단계로 진행되지 않는다.

 

간단히 말하자면 whitelist는 로그인하지않아도 접근할 수 있는 경로이다. 

접근하려는 페이지가 whitelist에 해당되면 isLoginCheckPath에서 false를 반환받고 chain.doFilter를 통해 다음 필터나 컨트롤러로 넘어갈 수 있다.

  해당되지않으면 세션을 통해 로그인 정보를 확인한다. 확인이 되면 특정페이지에 접근이 가능해지는 것이다. 확인되지않으면 로그인창으로 돌아간다. 이 경우 다음단계인 서블릿이 실행되지않아 Cotroller로 넘어갈 수가 없다.

 

 리다이렉트 경로를 추가해준이유는 로그인이 성공했으면 기존에 머물던 페이지로 돌아갈 수 있게끔 해주기 위해서이다. 안그러면 홈화면으로 돌아갈 수 있으니깐 말이다. 

 

참고로 ServletRequest request 는 HTTP 요청이 아닌 경우까지 고려해서 만든 인터페이스이다. HTTP를 사용하면 HttpServletRequest httpRequest = (HttpServletRequest) request; 와 같이 다운 케스팅 하면 된다.

 

 

 

 

WebConfig 

@Bean
public FilterRegistrationBean loginCheckFilter() {
 FilterRegistrationBean<Filter> filterRegistrationBean = new
FilterRegistrationBean<>();
 filterRegistrationBean.setFilter(new LoginCheckFilter());
 filterRegistrationBean.setOrder(2);
 filterRegistrationBean.addUrlPatterns("/*");
 return filterRegistrationBean;
}

필터를 등록하는 방법은 여러가지가 있지만, 스프링 부트를 사용한다면 FilterRegistrationBean 을 사용해서 등록하면 된다

 

setFilter(new LogFilter()) : 등록할 필터를 지정한다.

setOrder(2) : 필터는 체인으로 동작한다. 따라서 순서가 필요하다. 낮을 수록 먼저 동작한다.

addUrlPatterns("/*") : 필터를 적용할 URL 패턴을 지정한다. 한번에 여러 패턴을 지정할 수 있다.

 

 

 

 

참고

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

'SpringMVC' 카테고리의 다른 글

ArgumentResolver활용해보기  (1) 2024.02.01
스프링 인터셉터  (0) 2024.01.31
세션타임아웃설정  (0) 2024.01.31
서블릿http세션  (0) 2024.01.30
쿠키보안문제와 세션  (0) 2024.01.30