๐Ÿ“‚ ์Šคํ”„๋ง/๊ธฐ๋ณธ ๊ฐœ๋…

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(Servlet Filter)

Amenable 2023. 4. 29. 22:29

  ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(Servlet Filter)์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ณ , '์š”์ฒญ ๋กœ๊ทธ ์˜ˆ์ œ'์™€ '์ธ์ฆ ์ฒดํฌ ์˜ˆ์ œ'๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ป๊ฒŒ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค.

 

1. ๊ฐœ๋… ๐ŸŒŒ

๐Ÿ“˜ 1. ํ•„ํ„ฐ ํ๋ฆ„

  ํ•„ํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ๋ฆ„์„ ๊ฐ€์ง„๋‹ค.

HTTP ์š”์ฒญ → WAS → ํ•„ํ„ฐ → ์„œ๋ธ”๋ฆฟ(Dispatcher Servlet) → ์ปจํŠธ๋กค๋Ÿฌ

  ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋ฉด ํ•„ํ„ฐ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๊ทธ๋ฆฌ๊ณ  ์„œ๋ธ”๋ฆฟ์ด ํ˜ธ์ถœ๋œ๋‹ค. ์ฆ‰, ์„œ๋ธ”๋ฆฟ์ด ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ํ•„ํ„ฐ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๊ณ ๊ฐ์˜ ์š”์ฒญ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ฑฐ๋‚˜ ์ธ์ฆ ์ฒดํฌ(๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ๋“ฑ)๋“ฑ์˜ ํ–‰์œ„๋ฅผ ํ•„ํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“˜ 2. ํ•„ํ„ฐ ์ œํ•œ

  ํ•„ํ„ฐ์—์„œ๋Š” ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ๊ณผ ๊ฐ™์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ์š”์ฒญ์— ๋Œ€ํ•˜์—ฌ ํŒ๋‹จํ•˜๊ณ  ๊ฑฐ๊ธฐ์—์„œ ๋์„ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

(1) ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ
HTTP ์š”์ฒญ → WAS → ํ•„ํ„ฐ(๋กœ๊ทธ์ธ O) → ์„œ๋ธ”๋ฆฟ → ์ปจํŠธ๋กค๋Ÿฌ
(2) ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ
HTTP ์š”์ฒญ → WAS → ํ•„ํ„ฐ(๋กœ๊ทธ์ธ X)

๐Ÿ“˜ 3. ํ•„ํ„ฐ ์ฒด์ธ

  ํ•„ํ„ฐ๋Š” ์ฒด์ธ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

HTTP ์š”์ฒญ → WAS → ํ•„ํ„ฐ1 → ํ•„ํ„ฐ2 → ํ•„ํ„ฐ3 → ์„œ๋ธ”๋ฆฟ → ์ปจํŠธ๋กค๋Ÿฌ

  ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ํ•„ํ„ฐ๋ฅผ ๋จผ์ € ์ ์šฉํ•˜๊ณ  ๊ทธ๋ฆฌ๊ณ  ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“˜ 4. ํ•„ํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค

public interface Filter {

    default void init(FilterConfig filterConfig) throws ServletException {}
    
    void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    default void destroy() {}
}

  ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•„ํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ๋“ฑ๋กํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ํ•„ํ„ฐ๋ฅผ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•œ๋‹ค. ๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค.

  • init()
    ํ•„ํ„ฐ ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ
    ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.
  • doFilter()
    ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
    ํ•„ํ„ฐ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.
  • destroy()
    ํ•„ํ„ฐ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ
    ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.

  init()๊ณผ destroy()๋Š” default ๋ฉ”์„œ๋“œ์ด๋ฏ€๋กœ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์„ ๊ผญ ํ•ด์•ผ๋งŒ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

 

2. ์š”์ฒญ ๋กœ๊ทธ ์˜ˆ์ œ ๐Ÿช

@Slf4j
public class LogFilter implements Filter {

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

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

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

        String uuid = UUID.randomUUID().toString(); // HTTP ์š”์ฒญ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ

        try{
            log.info("REQUEST [{}][{}]", uuid, requestURI);
            chain.doFilter(request, response);
        } catch (Exception e) {
            throw e;
        } finally {
            log.info("RESPONSE [{}][{}]", uuid, requestURI);
        }
    }

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

  ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด HttpServletRequest๊ฐ€ ์•„๋‹Œ ServletRequest์ธ ์ด์œ ๋Š” ํ•„ํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค๋Š” HTTP ์š”์ฒญ์ด ์•„๋‹Œ ๊ฒฝ์šฐ๊นŒ์ง€ ๊ณ ๋ คํ•ด์„œ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ request๋ฅผ HttpServletRequest๋ผ๊ณ  ๋‹ค์šด์บ์ŠคํŒ… ํ•ด์ฃผ์—ˆ๋‹ค.

  chain.doFilter(request, response)๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‹ค์Œ ํ•„ํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์Œ ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์—†์œผ๋ฉด ์„œ๋ธ”๋ฆฟ์„ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๊ฑธ ์ƒ๋žตํ•˜๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ง„ํ–‰์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean logFilger() {
        FilterRegistrationBean<Filter> filterRegistrationBean
                = new FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(new LogFilter()); // ๋“ฑ๋กํ•  ํ•„ํ„ฐ ์ง€์ •
        filterRegistrationBean.setOrder(1); // ์ฒด์ธ ์ˆœ์„œ ์ง€์ •
        filterRegistrationBean.addUrlPatterns("/*"); // ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  URL ํŒจํ„ด ์ง€์ •
        return filterRegistrationBean;
    }
}

  FilterRegistrationBean์„ ์ด์šฉํ•ด์„œ ๋“ฑ๋กํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

  setFilter()๋ฅผ ์ด์šฉํ•ด์„œ ์‚ฌ์šฉํ•  ํ•„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๊ณ , setOrder()๋ฅผ ์ด์šฉํ•ด์„œ ์ฒด์ธ ์ˆœ์„œ๋ฅผ ์ •ํ•˜๊ณ , addUrlPatterns()๋ฅผ ์ด์šฉํ•ด์„œ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  URL์„ ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.

  ์‹คํ–‰์‹œ์ผœ ๋ณด๋ฉด ๋กœ๊ทธ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

2023-04-29T21:58:44.599+09:00 INFO 16520 --- [ main] com.filter.LogFilter : log filter init
2023-04-29T21:58:47.135+09:00 INFO 16520 --- [nio-8080-exec-1] com.filter.LogFilter : REQUEST [14e2840a-84d3-43a3-9275-f03fab226e31][/]
2023-04-29T21:58:47.661+09:00 INFO 16520 --- [nio-8080-exec-1] com.filter.LogFilter : RESPONSE [14e2840a-84d3-43a3-9275-f03fab226e31][/]
2023-04-29T21:59:05.150+09:00 INFO 16520 --- [ionShutdownHook] com.filter.LogFilter : log filter destroy

 

3. ์ธ์ฆ ์ฒดํฌ ์˜ˆ์ œ ๐ŸŒ

@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 (...) {
                    log.info("๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž ์š”์ฒญ {}", requestURI);
                    //๋กœ๊ทธ์ธ์œผ๋กœ redirect
                    httpResponse.sendRedirect("/login?redirectURL=" + requestURI);

                    // ๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž๋Š” ๋” ์ด์ƒ ์ง„ํ–‰ํ•˜์ง€ ์•Š๊ธฐ
                    return;
                }
            }

            // ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ฒฝ๋กœ์ด๊ฑฐ๋‚˜
            // ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ
            // ๊ณ„์† ์ง„ํ–‰
            chain.doFilter(request, response);
        } catch (Exception e) {
            throw e;
        } finally {
            log.info("์ธ์ฆ ์ฒดํฌ ํ•„ํ„ฐ ์ข…๋ฃŒ {}", requestURI);
        }
    }

    private boolean isLoginCheckPath(String requestURI) {
        return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
    }
}
@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean loginCheckFilger() {
        FilterRegistrationBean<Filter> filterRegistrationBean
                = new FilterRegistrationBean<>();

        filterRegistrationBean.setFilter(new LoginCheckFilter()); // ๋“ฑ๋กํ•  ํ•„ํ„ฐ ์ง€์ •
        filterRegistrationBean.setOrder(2); // ์ฒด์ธ ์ˆœ์„œ ์ง€์ •
        filterRegistrationBean.addUrlPatterns("/*"); // ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  URL ํŒจํ„ด ์ง€์ •
        return filterRegistrationBean;
    }
}

  'ํ™ˆ, ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ, css'์™€ ๊ฐ™์€ ๊ณณ์—๋Š” ์ธ์ฆ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•ญ์ƒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ whitelist๋ผ๋Š” ๊ฒƒ์„ ๋งŒ๋“ค์–ด์„œ ์ธ์ฆ ์ฒดํฌ ๋กœ์ง์—์„œ ๋ฐฐ์ œํ•ด ์ฃผ์—ˆ๋‹ค.

  ์ธ์ฆ์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด login ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•˜๊ฒŒ ํ•˜์˜€๋Š”๋ฐ, ๋’ค์— redirectURL์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ๋กœ๊ทธ์ธ์„ ํ•œ ์ดํ›„ ๋‹ค์‹œ ์›๋ž˜ ํŽ˜์ด์ง€๋กœ ๋Œ์•„์˜ค๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค. 

 

  ์ถ”๊ฐ€์ ์œผ๋กœ ์ธํ„ฐ์…‰ํ„ฐ(Interceptor)์™€ ๋‹ฌ๋ฆฌ ํ•„ํ„ฐ๋Š” doFilter(request, response)๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ request์™€ response๋ฅผ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ฐธ๊ณ  ์‚ฌํ•ญ์œผ๋กœ ์•Œ์•„๋‘์ž.

 

ํ•ด๋‹น ๊ธ€์€ ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ '์„ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.