본문 바로가기

Back-End/Spring-MVC

Servlet Filter

서블릿 필터에 대해 알아보자

공통 관심사란?

애플리케이션에서 여러 로직이 공통적으로 신경 써야 하는 문제를 공통 관심사라고 한다.
예를 들어:
로그인하지 않은 비회원 유저가 상품 관리 페이지나 중요한 데이터에 접근하면 큰 문제가 발생할 수 있다.
이를 방지하려면 어떻게 해야 할까?

  • 각 컨트롤러 메서드에 “로그인 여부 체크 로직”을 하나하나 작성해야 할 수도 있다.
  • 하지만 이 방법은 복잡하고, 중복 코드가 많아지고, 유지보수가 어렵다.
  • 만약 로그인 로직이 바뀌면 모든 코드를 수정해야 한다! 😱

공통 관심사를 해결하는 방법: 서블릿 필터

서블릿 필터는 이런 공통 관심사를 처리하기 위해 사용된다.
특히 웹 애플리케이션에서 HTTP 요청과 응답을 가로채 처리하는 데 유용하다.


서블릿 필터의 동작 흐름

  • 서블릿 필터 흐름
    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
  • 필터 제한
    HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러 (로그인 사용자)
    HTTP 요청 -> WAS -> 필터(적절하지 않은 요청이라 판단 후 서블릿 호출 X) (비회원 사용자)
  • 필터 체인
    HTTP 요청 -> WAS -> 필터1 -> 필터2 -> 필터3 -> 서블릿 -> 컨트롤러

1. Filter 구현하고 인증체크하기

public class CustomFilter implements Filter {
    
    private static final String[] whitelist = {"/", "/members/singup", "/login", "/logout"};
    
    @override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
		//HttpServlet 기능이 더 많이 때문에 캐스팅을 해줘야한다!
        HttpServletRequest httpRequest = (HttpServeltRequest) request;
        String requestURI = httpRequest.getRequestURI(); //요청 URI 받기
        
        HttpServletResponse httpResponse = (HttpServletResponse) response;
	
        try {        
           if(isWhitelist(requestURI)) {
              HttpSession session = httpRequest.getSession(false);
              if(session == null || session.getAttribute(SessionConst.LOGIN_USER) == null) {
                 log.info("미인증 사용자 요청 {}", requestURI);
                 throw new RuntimeException("로그인 해주세요");
               }
             }          
            chain.doFilter(request, response);
         } catch (Exception e) {
            throw e;
         } finally {
            log.info("인증 체크 필터 종료");
         }            
     }
    
    //화이트 리스트의 경우 인증 체크 X
    private boolean isWhitelist(String resultURI) {
    	return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
	}        
    
}

코드 설명 

  • 화이트리스트 확인
    if (!isWhitelist(requestURI)) :
    방문자가 지나가려는 문(requestURI)이 “경비원이 신분증 확인 없이도 통과할 수 있는 문(화이트리스트)“인지 확인한다.
    만약 화이트리스트에 포함되지 않은 문이라면, 신분증 확인 절차를 진행한다.
  • 세션 확인
    HttpSession session = httpRequest.getSession(false) :
    방문자가 "로그인해서 받은 신분증(세션)"을 가지고 있는지 확인한다.
    getSession(false)는 이미 존재하는 세션이 없으면 새로운 세션을 만들지 않고 null을 반환한다.
  • 세션에 로그인 정보 확인
    if(session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) :
    신분증(세션)이 없거나, 신분증 안에 회원 정보가 없으면, "미인증 사용자 입니다! 통과할 수 없습니다"라고 요청을 막는다.
  • 요청 허용
    위 조건을 모두 통과하면 요청을 처리하도록 다음 단계(컨트롤러)로 넘긴다.

주요 포인트

  • chain.doFilter(request, response) : 이 부분이 가장 중요한데 다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출한다. 만약 이 로직을 호출하지 않으면 다음 단계로 진행되지 않는다.
  • 화이트리스트 경로(로그인/회원가입)는 필터를 통과하지 않음.
  • 비회원 사용자의 요청은 session을 확인하여 차단

2. Filter를 쓸 수 있게 등록을 해줘야 한다.

@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean customFilter() {
    	FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new CustomFilter()); //등록할 필터를 지정
        filterRegistrationBean.setOrder(1); // chain 순서
        filterRegistrationBean.addUrlPatterns("/*"); 
        
        return filterRegistrationBean;
}

마무리

서블릿 필터는 로그인 여부, 인증 로직, 공통 관심사를 깔끔하게 처리할 수 있다.
코드가 중복되지 않아 유지보수가 쉬워지고, 확장성도 높아진다.

'Back-End > Spring-MVC' 카테고리의 다른 글

JWT(Json Web Token)  (0) 2025.01.04
스프링 글로벌 API 예외 처리와 @Valid 검증 예외 처리  (1) 2024.12.31
Cookie와 Session  (0) 2024.12.12
HTTP 요청 / 응답 조합 상황별 사용  (0) 2024.12.02
HTTP 응답 데이터  (1) 2024.12.02