본문 바로가기

Spring/Spring

[Spring] 필터를 이용한 로그인 처리

반응형

필터란?

필터는 서블릿이 제공하는 기능으로 말 그대로 무언가를 걸러주는 역할을 한다.

웹사이트에서는 기본적으로 로그인 후에 다양한 기능들을 사용할 수 있지만 만약 로그인을 하지 않고 바로 내가 들어가고 싶은 기능의 URI를 입력해서 들어간다면 로그인을 하는 의미가 없어진다. 이는 공통 관심사 (cross-cutting concern)와도 연관이 있는데 웹사이트, 애플리케이션을 이용할 때 그 기능들을 이용하기 위해서는 로그인처럼 자신을 인증해야 한다. 이는 여러 기능들이 인증이라는 부분에 대해 관심을 가지고 있다고 말한다. 공통 관심사를 해결하기 위해서는 스프링의 AOP를 사용할 수도 있지만 웹과 관련된 부분은 서블릿 필터 또는 스프링 인터셉터를 사용하는 것이 좋다.

 

서블릿 필터 흐름

HTTP 요청 → WAS   필터   서블릿 (디스패처 서블릿)    컨트롤러

필터 체인

HTTP 요청 → WAS   필터1 → 필터2 → 필터3 →   서블릿 (디스패처 서블릿)   컨트롤러

필터를 여러개 추가할 수도 있다.

필터 제한

HTTP 요청 → WAS → 필터 (판단 후에 걸러야 한다고 판단되면 다음 단계로 안 넘어감)

 

Filter 인터페이스와 메서드

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(), destroy() 메서드는 default이기 때문에 따로 구현을 안 해주어도 된다.

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);
                  
                    httpResponse.sendRedirect("/login?redirectURL=" + requestURI);
                    return; // return을 하면 다음 서블렛이나 컨트롤러 호출 안 하고 끝나버림. redirect 호출해서 그 페이지로 가버림
                }
            }

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

1. ServletRequest, ServletResponse는 HttpServletRequest, HttpServletResponse의 부모이다. HttpServletRequest, HttpServletResponse가  더 부가기능이 많으므로 downcasting 해서 사용한다.

(ServletRequest, ServletResponse를 기능으로 받은 이유는 http 요청 말고도 다른 것을 받을 수도 있기 때문이다.)

2. HttpSession으로 세션을 가져왔는데 세션이 null이거나 세션의 LOGIN_MEMBER가 null이라면 로그인을 하지 않은 사용자라는 것이기 때문에 미인증 사용자 요청 로그가 뜬다.

(로그인을 했다면 session에 LOGIN_MEMBER 부분에 멤버 객체가 들어가있음)

 

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LogFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");

        return filterRegistrationBean;
    }

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

        return filterRegistrationBean;
    }
}

스프링부트에서 필터를 등록하는 법은 FilterRegistrationBean을 사용하는 것이다.

setFiler(new LoginCehckFilter()) - 등록하고자 하는 필터의 이름을 넣는다.

setorder() - 필터는 체인으로 동작한다. 순서가 낮을수록 먼저 동작한다.

addUrlPatterns() - 필터를 적용할 URL 패턴을 넣는다. (/*은 모든 url에 다 적용된다.)

반응형