doFilter,doFilterInetnal

Terror·2024년 8월 25일

Filter

  • jwt의 인증,인가 처리에 대해 공부하면서 빠질수없는 doFilter,doFilterInternal을 조금더 자세히 봐보도록하자
  • 근데 그 전에 forward,redirect의 개념을 공부하면서 Http의 요청 처리에를 알아볼필요가있으니 함께 봐보자

redirect

  • 흐름
    1. 클라이언트 -> 서버 URL요청
    2. 서버는 해당 URL을 찾지못하거나, 다른이유로 클라이언트에게 300번대(302)와 함께 다른 URL로 요청하라는 응답 보냄
    3. 클라이언트는 새롭게 변경된 URL로 -> 서버 재요청
    4. 서버는 해당 URL에 올바르게 응답
  • 위 그림을 확인해서도 알 수 있다싶이, 첫번째,두번째 req객체가 다름을 확인 할 수 있다 (클라이언트는 새로운 요청을 2번한것이다)
  • 첫번째 요청을 GET으로 하였든, POST로 하였던 리다이렉트되서 다시 요청할때는 무조건 GET이다

Forward

  • 흐름
    1. 클라이언트가 /hello 요청
    2. 서버는 /hello를 자신이 처리할게 아니라면 /hello 를 통해서 요청받은 (req,ㄱres)객체의 내용을 그대로 jsp로 내용전달
    3. /hello가 응답을 보냄

Spring 에서는 어떻게 처리될까?

Redirect

  • redirect로 응답할 때 RedirectView를 통해 응답헤더 생성된다
  1. 클라이언트에서 요청 보냄
  2. DispathcerServlet이 요청을받고, 올바른 URL인 컨트롤러에 매핑
public String save(User user, Model model) throw Exception {
  Strign msg = URLEncoder.encode("id 틀림",utf-8);
  model.addAttribute("msg",msg)
  return "redirect:/register/add";
}
  1. 컨틀롤러는 "redirect:/register/add"을 DispathcerServlet에 반환해주고 RedirectView에서 응답헤더 생성
  2. 클라이언트는 위 응답을 바탕으로, 로케이션으로 정보 재요청
  3. DispathcerServlet에서 요청에 맞는 컨트롤러의 메서드 호출

forward

  • forward로 응답할때는 internalResourceView를 통해 내부적으로 forward가 생성됨

doFilter

사전적 정의

  • doFilter()는 최초 실행시 ServletRequest 객체에 자신의 이름과 수행하였음을 표시하기 위한 boolean의 true값을 함께 넣어두고, doFilterInternal()을 통해 자신의 기능 수행
  • redirect 등으로 다시 실행되는 경우 이 전 수행에서 요청 객체에 담아뒀던 수행 여부를 확인한후, 이미 수행되었다고 판단되면 Filter Chain에게 요청과 응답 객체를 전달 해주는 방식으로 동작됨
    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request instanceof HttpServletRequest httpRequest) {
            if (response instanceof HttpServletResponse httpResponse) {
                String alreadyFilteredAttributeName = this.getAlreadyFilteredAttributeName();
                boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
                if (!this.skipDispatch(httpRequest) && !this.shouldNotFilter(httpRequest)) {
                    if (hasAlreadyFilteredAttribute) {
                        if (DispatcherType.ERROR.equals(request.getDispatcherType())) {
                            this.doFilterNestedErrorDispatch(httpRequest, httpResponse, filterChain);
                            return;
                        }

                        filterChain.doFilter(request, response);
                    } else {
                        request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);

                        try {
                            this.doFilterInternal(httpRequest, httpResponse, filterChain);
                        } finally {
                            request.removeAttribute(alreadyFilteredAttributeName);
                        }
                    }
                } else {
                    filterChain.doFilter(request, response);
                }

                return;
            }
        }


1. hasAlreadyFilteredAttribute가 맨처음 false라는것은 처음들어왔다는 뜻이기때문에
2. 밑의 else 구문으로 빠지게되고 true로 바꿔준다

3. 그 다음 만약 동일한 doFilter요청이 들어왔을때 boolena값을 보고 true라면
이미 실행이 됐었다는 뜻이기때문에 동일한 객체라고 인식하고 그다음 doFiletInternal() 메서드를 호출한다

doFilterInternal

  • 얘는 별거없다
  • 그냥 http요청이 들어올때 한번씩 호출되는 필터라고 생각하면된다
  • 애초에 doFilter가 호출될떄 연쇄적으로 호출되는 필터이기때문에 어찌보면 당연하다
  • 보통 인증,인가,로깅,모니터링등을 한다

정리

  1. OncePerRequestFilter 요청이 여러번 반복해서 처리되는것을 방지하기위한 추상 클래스이다
  2. doFilter는 기본적인 필터링 로직(요청 중복 필터링 제외시키기, 다음 필터체인으로 넘기게하기)
  3. 상세한 필터로직 (인증,인가 처리등등)
  4. 이렇게 클래스를 분할함으로써 역할을 분리 시킨것이다
  5. 실제로 우리가 jwt 인가 처리할때를 보면, doFilterInternal() 메서드만 오버라이딩해서 처리한것을 확인 할 수 있다
  6. 즉 우리가 OncePerRequestFilter를 사용하였다는것은, http 요청이 한번 들어올떄마다 처리하고싶은것을 사용하고싶다는 뜻이며
  7. 그 상세한 필터링 로직을 구현하려면 doFilterInternal()을 오버라이딩하여 처리가능하다 !

참조 블로그

https://byungmin.tistory.com/71

profile
테러대응전문가

0개의 댓글