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

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

by rlaehddnd0422

์š”๊ตฌ์‚ฌํ•ญ์„ ๋ณด๋ฉด ๋กœ๊ทธ์ธ ํ•œ ์‚ฌ์šฉ์ž๋งŒ ์ƒํ’ˆ ๊ด€๋ฆฌ ํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋กœ๊ทธ์ธ์„ ํ•˜์ง€ ์•Š์•„๋„ URL์„ ํ†ตํ•ด ์ƒํ’ˆ ๊ด€๋ฆฌ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

  • http://localhost:8080/items

์ƒํ’ˆ ๊ด€๋ฆฌ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋Š” ๋กœ์ง์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž‘์„ฑํ•˜๋ฉด ๋˜๊ฒ ์ง€๋งŒ, ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ, ์กฐํšŒ ๋“ฑ๋“ฑ ์ƒํ’ˆ๊ด€๋ฆฌ์˜ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ ๋กœ์ง์— ๊ณตํ†ต์œผ๋กœ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋กœ์ง์ด ์ƒ๊ธฐ๊ธฐ๋ผ๋„ ํ•œ๋‹ค๋ฉด ๋˜ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋Š” ๋กœ์ง๊นŒ์ง€ ์ƒ๊ฐํ•ด์„œ ์งœ์•ผํ•ฉ๋‹ˆ๋‹ค. ์—„์ฒญ ๊ท€์ฐฎ์€ ์ผ์ž…๋‹ˆ๋‹ค.

 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—ฌ๋Ÿฌ ๋กœ์ง์—์„œ ๊ณตํ†ต์œผ๋กœ ๊ด€์‹ฌ์ด ์žˆ๋Š” ๊ฒƒ์„ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋Š” ์Šคํ”„๋ง์˜ AOP - @Around ๋ฅผ ์ด์šฉํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์›น๊ณผ ๊ด€๋ จ๋œ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋‚˜ ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

 

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ

ํ•„ํ„ฐ๋Š” ์ž๋ฐ” ํ‘œ์ค€ ์ŠคํŽ™์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. 

ํ•„ํ„ฐ๋ฅผ ์ ์šฉ ์‹œ

HTTP Request โ–ถ๏ธŽ WAS โ–ถ๏ธŽ ํ•„ํ„ฐ โ–ถ๏ธŽ ์„œ๋ธ”๋ฆฟ โ–ถ๏ธŽ ์ปจํŠธ๋กค๋Ÿฌ 

์ค‘๊ฐ„์— ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์ณ์„œ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ( ์—ฌ๊ธฐ์„œ ์„œ๋ธ”๋ฆฟ์€ DispatcherServlet ( FrontController ) )

ํ•„ํ„ฐ์—์„œ ๊ฑธ๋ฆฌ๊ฒŒ ๋˜๋ฉด ์ ์ ˆํ•˜์ง€ ์•Š์€ ์š”์ฒญ์ด๋ผ ํŒ๋‹จํ•ด ์„œ๋ธ”๋ฆฟ์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

+ ํ•„ํ„ฐ๋Š” ์ฒด์ธ์œผ๋กœ ๊ตฌ์„ฑ๋˜๋Š”๋ฐ, ์ค‘๊ฐ„์— ํ•„ํ„ฐ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

HTTP Request โ–ถ๏ธŽ 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() : ํ•„ํ„ฐ์˜ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๋กœ์ง ๊ตฌํ˜„ ์ดํ›„ chain.doFilter(request,response) ํ•„์ˆ˜ 
  • destroy() : ํ•„ํ„ฐ ์ข…๋ฃŒ ๋ฉ”์†Œ๋“œ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„  ๋จผ์ € ์š”์ฒญ์— ๋Œ€ํ•ด ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๋‹จ์ˆœํ•œ ํ•„ํ„ฐ๋ฅผ ํ•„ํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@Slf4j
public class LogFilter implements Filter {

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

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

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        log.info("log filter doFilter");
        HttpServletRequest httpRequest = (HttpServletRequest) request; // ๋‹ค์šด ์บ์ŠคํŒ…
        String requestURI = httpRequest.getRequestURI();
        String uuid = UUID.randomUUID().toString();
        try
        {
            log.info("REQUEST [{}][{}]",uuid,requestURI);
            chain.doFilter(request,response);
        }catch(Exception e){
            throw e;
        }finally {
            log.info("RESPONSE [{}][{}]",uuid,requestURI);
        }
    }
}
  • init()๊ณผ destroy()๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— default๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด ๊ตฌํ˜„ํ•ด ์ฃผ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.
  • ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ doFilter(ServletRequest request , ServletResponse response, FilterChain chain) ์ž…๋‹ˆ๋‹ค.
  • ServletRequest, ServletResponse๋Š” HttpServletRequest์˜ ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ HTTP ์š”์ฒญ,์‘๋‹ต์ด ์•„๋‹Œ ๊ฒฝ์šฐ๊นŒ์ง€ ๊ณ ๋ คํ•ด์„œ ๋งŒ๋“  ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.
  • HTTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด HttpServletRequest, HttpServletResponse๋กœ ๋‹ค์šด ์บ์ŠคํŒ…ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • try์—์„œ ์š”์ฒญ์— ๋Œ€ํ•œ URI์™€ UUID๋ฅผ ์–ป์–ด ๋กœ๊ทธ์— ๋‚จ๊ฒจ์ค๋‹ˆ๋‹ค. ( ์˜ˆ์™ธ๋ฐœ์ƒ ์‹œ ๋ณ„๋„์˜ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์ง„ ์•Š์•˜์Šต๋‹ˆ๋‹ค )
    • ์—ฌ๊ธฐ์„œ chain.doFilter(request,response)๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
    • ๋‹ค์Œ ํ•„ํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœ. ํ•„ํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์„œ๋ธ”๋ฆฟ์„ ํ˜ธ์ถœ. ๋งŒ์•ฝ ์ด ๋กœ์ง์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ง„ํ–‰ํ•˜์ง€ ์•Š๊ธฐ ๋–„๋ฌธ์— ํ•„์ˆ˜์ ์œผ๋กœ ์ž‘์„ฑํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

 

1. @Component๋กœ ์ž๋™ ๋“ฑ๋ก

@Component
@WebFilter("urlPatterns='/*")
public class LogFilter implements Filter {

์ž๋™ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ @WebFilter๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด urlPattern์„ ์ง€์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  url ํŒจํ„ด์— ์ „์ฒด์— ์ ์šฉ์ด ๋ฉ๋‹ˆ๋‹ค. ๋‹จ์ ์€ ํ•„ํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ธ ๊ฒฝ์šฐ ์ˆœ์„œ์ง€์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

2. FilterRegistrationBean์„ ์‚ฌ์šฉํ•ด์„œ ๋“ฑ๋ก

- ์ˆ˜๋™์œผ๋กœ ๋“ฑ๋ก @Configuration์— @Bean์œผ๋กœ FilterRegistrationBean์„ ๋“ฑ๋กํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

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

        return filterFilterRegistrationBean;
    }
  • setFilter(new LogFilter())๋กœ ๋“ฑ๋กํ•  ํ•„ํ„ฐ ์ง€์ •. 
  • setOrder(1): ํ•„ํ„ฐ๋Š” ์ฒด์ธ์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ˆœ์„œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚ฎ์„์ˆ˜๋ก ๋จผ์ € ๋™์ž‘
  • addUrlPatterns(): ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  URL ํŒจํ„ด์„ ์ง€์ •. ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ํŒจํ„ด๋„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ ์™ธ์˜ ํ•„ํ„ฐ ์„ค์ • ๋ฐฉ๋ฒ•์€ ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

https://jronin.tistory.com/124

 

[Spring boot] Filter ์„ค์ •

spring boot ํ•™์Šต & ์„ธํŒ… 3ํƒ„ (2.3.9 RELEASE docs.spring.io/spring-boot/docs/2.3.9.RELEASE/reference/html/) 1. @Component ๋˜๋Š” @ServletComponentScan WebFilter) ์ž„๋ฒ ๋””๋“œ WAS์˜ ๊ฒฝ์šฐ, ์ž๋™ ์„ค์ •์— ์˜ํ•ด์„œ Filter๋ฅผ ๊ตฌํ˜„ํ•  ํด๋ž˜์Šค์— @Co

jronin.tistory.com

 

์ด์ œ ํ•„ํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋งŒ URL์„ ํ†ตํ•ด ์ƒํ’ˆ ๊ด€๋ฆฌ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ , ๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๋Š” ์ƒํ’ˆ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์„ค์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

private static final String[] whiteList = {"/","/members/add","/login","/logout","/css/*"};

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
{
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    String requestURI = httpRequest.getRequestURI();

    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; // ์ค‘์š”
            }
        }   
	 chain.doFilter(request,response); // ํ•„์ˆ˜!  
     
     }catch..finally ..
}
    
private boolean isLoginCheckPath(String requestURI)
{
    return !PatternMatchUtils.simpleMatch(whiteList,requestURI);
}

 

ํ™”์ดํŠธ ๋ฆฌ์ŠคํŠธ(ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, css)์— ์žˆ๋Š” URI๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  URI์— ์ ์šฉ์‹œ์ผœ ์„ธ์…˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๊ทธ์ธ ํ•œ ๊ฒฝ์šฐ(์„ธ์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ) ์—๋งŒ ์ƒํ’ˆ ๊ด€๋ฆฌ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•„ํ„ฐ๋ฅผ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. 

  • ์„ธ์…˜์ด ์—†๊ฑฐ๋‚˜, ์„ธ์…˜์— "loginMember"์˜ loginMember๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž ์š”์ฒญ์œผ๋กœ ํŒ๋‹จํ•ด ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ํ•ฉ๋‹ˆ๋‹ค. 
  • ์ด ๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ฟผ๋ฆฌ๋กœ requestURI๋ฅผ ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ์˜ @RequestParam์œผ๋กœ ๋„˜๊ฒจ์„œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ดํ›„ requestURI๋กœ ์ž๋™์œผ๋กœ ์ด๋™ํ•˜๋„๋ก ์„ค์ •.
@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm loginForm, BindingResult bindingResult,
                      @RequestParam(defaultValue = "/") String redirectURL,
                      HttpServletRequest request, HttpServletResponse response)
{
...

// ์„ฑ๊ณต์ฒ˜๋ฆฌ ...
// ์„ธ์…˜ ์ฒ˜๋ฆฌ ...
retrun "redirect:" + redirectURL;
}
  • ๊ทธ ์ดํ›„ return;
    • ์ธ์ฆ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ : finally๊นŒ์ง€ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ
    • ๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ return ํ•ด ์คŒ์œผ๋กœ์จ ๋‹ค์Œ์œผ๋กœ ์ง„ํ–‰๋˜์ง€ ์•Š๊ณ  ๋.

 

ํ•„ํ„ฐ ๋“ฑ๋ก

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

        return filterFilterRegistrationBean;
    }

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

        return filterFilterRegistrationBean;
    }
}
๐Ÿšฉ Flow
HTTP Request โ–ถ๏ธŽ WAS โ–ถ๏ธŽ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ํ•„ํ„ฐ โ–ถ๏ธŽ ๋กœ๊ทธ์ธ ์ฒดํฌ ํ•„ํ„ฐ โ–ถ๏ธŽ ์„œ๋ธ”๋ฆฟ โ–ถ๏ธŽ ์ปจํŠธ๋กค๋Ÿฌ 

์ด๋ ‡๊ฒŒ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋ฅผ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๊ฒฐํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ