본문 바로가기
Spring Study/MVC 패턴

[MVC 패턴] 로그인 처리2 - 필터, 인터셉트

by 정재인 2023. 8. 31.

서블릿 필터

필터흐름

HTTP 요청 → WAS → 필터 → 서블릿 → 컨트롤러

 

필터 제한

HTTP 요청 → WAS → 필터 → 서블릿 → 컨트롤러  //로그인 사용자
HTTP 요청 → WAS → 필터(적절하지 않은 요청이라 판단, 서블릿 호출X)  //비 로그인 사용자

필터에서 적절하지 않은 요청이라고 판단하면 필터에서 끝을 낼 수 있다. 따라서 로그인 여부를 체크하기 좋다.

 

필터 체인

HTTP 요청 → 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(): 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.

- destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.

 


스프링 인터셉터

 

스프링 인터셉터 흐름

HTTP 요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터 → 컨트롤러

 

스프링 인터셉터 제한

HTTP 요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터 → 컨트롤러  //로그인 사용자
HTTP 요청 → WAS → 필터 → 서블릿 → 스프링 인터셉터(적절하지 않은 요청이라 판단, 컨트롤러 호출X)  //비 로그인 사용자

인터셉터에서 적절하지 않은 요청이라고 판단하면 인터셉터에서 끝낼 수 있다. 따라서 로그인 여부를 체크하기 좋다.

 

스프링 인터셉터 체인

HTTP 요청 → WAS → 필터 → 서블릿 → 인터셉터1 → 인터셉터2 → 컨트롤러

스프링 인터셉터는 체인으로 구성되는데, 중간에 인터셉터를 자유롭게 추가할 수 있다. 예를 들어, 로그를 남기는 인터셉터를 먼저 적용하고, 그 다음에 로그인 여부를 체크하는 인터셉터를 만들 수 있다.

 

스프링 인터셉터 인터페이스

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {}
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}

- 인터셉터는 컨트롤러 호출 전(preHandle), 호출 후(postHandle), 요청 완료 이후(afterCompletion)과 같이 단계적으로 잘 세분화 되어 있다.

- 인터셉터는 어떤 컨트롤러(handler)가 호출되는지 호출 정보도 받을 수 있다. 또한 어떤 modelAndView가 반환되는지 응답 정보도 받을 수 있다.

 

정상 흐름

- preHandle: 컨트롤러 호출 전 호출된다.

  preHandle의 응답 값이 true이면 다음으로 진행하고, false면 더 진행하지 않는다. 

- postHandle: 컨트롤러 호출 후 호출된다.

- afterCompletion: 뷰가 렌더링 된 이후에 호출된다.

 

예외 발생

- preHandle: 컨트롤러 호출 전에 호출된다.

- postHandle: 컨트롤러에서 예외가 발생하면 postHandle은 호출되지 않는다.

- afterCompletion: afterCompletion은 항상 호출된다. 이 경우 예외를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.

 


ArgumentResolver 활용

@GetMapping("/")
public String homeLoginV3ArgumentResolver(@Login Member loginMember, Model model) {

    //세션에 회원 데이터가 없으면 home 
    if (loginMember == null) {
        return "home";
      }
    
    //세션이 유지되면 로그인으로 이동 
    model.addAttribute("member", loginMember);
    return "loginHome";
}

 

@Login 애노테이션 생성

package hello.login.web.argumentresolver;
  
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
  
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
    public @interface Login {
}

- @Target(ElementType.PARAMETER): 파라미터에만 사용

- @Retention(RetentionPolicy.RUNTIME): 리플렉션 등을 활용할 수 있도록 런타임까지 애노테이션 정보가 남아있음

- @Login을 사용해 좀 더 쉽게 로그인 정보를 조회할 수 있다.

댓글