쌓고 쌓다

[스프링 부트] 인터셉터 인증 체크 - 33 본문

프로그래밍/spring

[스프링 부트] 인터셉터 인증 체크 - 33

승민아 2023. 10. 5. 16:34

로그인하지 않은 유저가 게시글 작성을 시도하는 경우, 게시글 작성 컨트롤러를 호출하지 못하게 해보자.

 

먼저, 스프링 인터셉터의 흐름을 보자.

HTTP 요청 -> WAS -> 필터 -> 서블릿(디스패처 서블릿) -> 스프링 인터셉터 -> 컨트롤러

스프링 MVC의 시작점이 디스패처 서블릿이고

스프링 인터셉터 또한 스프링 MVC의 기술이기에 디스패처 서블릿 이후에 사용된다.

 

스프링 인터셉터를 통해 사용자의 요청을 제한할 수 있는데.

로그인 유저와 비 로그인 유저의 요청이 어떻게 처리 되는지 보자.

1. 로그인 사용자
 HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러

2. 비 로그인 사용자
 HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 (적절한 요청이 아니라고 판단하고, 컨트롤러 호출 X)

물론 인터셉터들을 체인하여

인터셉터1 -> 인터셉터2 -> 인터셉터3로 순서를 지정하여 차례대로 호출할 수 있다.

 

스프링 인터셉터 사용 방법

스프링 인터셉터를 사용하려면 HandlerInterceptor 인터페이스를 통해 구현해야한다.

public interface HandlerInterceptor {

	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
		return true;
	}
    
	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 : 컨트롤러 호출 전 호출 ( 정확히는 핸들러 어댑터 호출 전 )
    • 반환 값이 true라면, 정상 진행이 되고, false라면 핸들러 어댑터도 호출하지 않고 나머지 인터셉터도 호출하지 않는다.
    • 예외 발생시 postHandle을 호출하지 않는다.
  • postHandle : 컨트롤러 호출 후 호출 ( 정확히는 핸들러 어댑터 호출 후 )
  • afterCompletion : 뷰가 렌더링 된 이후에 호출
    • afterCompletion은 예외가 발생하더라도 항상 호출되므로 예외와 무관하게 공통처리에 유용함.
    • 예외를 파라미터로 받으므로 예외를 찍어볼 수 있다.

 

로그인 체크 스프링 인터셉터 개발

@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        log.info("인증 체크 인터셉터 실행 {}", requestURI);

        HttpSession session = request.getSession(false);
        if(session==null||session.getAttribute(SessionConst.LOGIN_MEMBER)==null) {
            log.info("미인증 사용자 요청");
            response.sendRedirect("/?redirectURL="+requestURI);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("[loginCheckInterceptor] postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("[loginCheckInterceptor] afterCompletion");
    }
}

게시글 작성 버튼을 눌렀을때

컨트롤러 호출전에 로그인 여부 체크만하면 됨으로 preHandle에만 로직을 작성하면 된다.

로직은 세션이 존재하는지 아닌지에 맞춰 true, false를 반환하도록 하면 된다.

 

인터셉터 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 로그 인터셉터
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**", "/*.ico", "/error", "/js/**");
        // 인증 인터셉터 등록 (로그인 체크)
        registry.addInterceptor(new LoginCheckInterceptor())
                .order(2)
                .addPathPatterns("/posters/FREE/write", "/posters/QUESTION/write");
    }

}

WebMvcConfigurer가 제공하는 addInterceptors()로 인터셉터를 등록할 수 있다.

addPathPatterns로 모든 경로를 인증 체크하고 excludePathPatterns로 제외하는것보다

체크할 경로만 추가하는게 좋을 것 같았다.

 

구현 모습

작성하기 버튼 클릭시 게시글 작성 컨트롤러는 실행되지 않고 "/"으로 redirect된다.

Comments