유저 프로필 페이지나, 업로드 페이지 등은 로그인한 유저만 접근 가능한 페이지여야한다. 이 때 문제가 초기화면을 로그인창으로 설정해 놓는다 하여도 url 입력을 통해 상기의 페이지들에 접근이 가능하다. 이를 방지하기 위해 로그인, 회원가입을 외한 모든 페이지에 로그인 체크 로직을 수행하고, 로그인 되어있지 않다면 로그인창으로 redirect 시킬 무언가가 필요하다.
즉 모든 Url 요청마다 로그인을 체크하는 공통처리를 수행해야하는데, 웹 관련 공통처리는 필터나 인터셉터를 사용한다.
필터란 서블릿이 제공하는 웹 관련 공통처리 방식이다. 서블릿 호출전 요청되며, 스프링에서는 디스패쳐 서블릿 호출 전과 디스패쳐 서블릿이 최종 응답을 반환할 때 호출된다. Filter 인터페이스의 doFilter 메서드를 오버라이딩 하여 구현하고, FilterRegistrationBean 에 등록하여 사용한다. doChain 으로 다음 필터를 호출할 수 있고, 중간에 중단시킬수도 있다.
인터셉터란 스프링이 제공하는 웹 관련 공통처리 방식이다. 디스패쳐 서블릿 이후 핸들러 어댑터 호출전, 핸들러 어댑터 결과 반환 후, 뷰 렌더링 후에 각각 호출된다. HandlerInterceptor 인터페이스의 perHandle, postHandle, afterCompletion 를 오버라이딩 하여 구현하고, WebMvcConfigurer 인터페이스의 addInterceptors 메서드에서 등록한다. 각 메서드 값이 true 면 다음 인터셉터를 호출하고 false 면 처리를 종료한다.
둘의 가장 큰 차이는 호출 시점이 다르다는 것이다. 필터는 디스패쳐 서블릿 전, 인터셉터는 디스패쳐 서블릿 후에 호출된다.
그 말은 필터에서 예외가 발생하면 디스패쳐 서블릿 호출전이므로 ExceptionResolver 를 사용할 수 없다는 것이다. ExceptionResolver 도 결국 디스패쳐 서블릿이 호출하는 것이기 때문이다. 그래서 @ControllerAdvice 와 @ExceptionHandler 를 통한 스프링의 편리한 예외처리를 하나도 사용할 수 없게되고, 예외가 WAS까지 던져져 재요청이 이루어질 것이다.
따라서 스프링을 사용한다면 예외처리와 유연성면에서 인터셉터를 사용하자.
AOP 는 CGLIB 기술로 특정 메서드의 앞 뒤에 공통 부가기능을 추가할 수 있게 해준다. 반면 인터셉터는 특정 Url 의 요청에 공통 부가기능을 수행한다. 그런데 로그인 확인 기능도 RequestMapping 된 핸들러 메서드의 앞 뒤에 로그인 검증로직을 추가하여 사용 가능하다. 그러면 왜 굳이 인터셉터를 사용할까?
AOP 는 파라미터로 JoinPoint나 ProceedingJoinPoint 를 갖는다. 반면 인터셉터는 파라미터로 HttpServlerRequest 와 HttpServletResponse 를 갖기에 웹 관련 공통로직을 처리하기에 더 편리하다.
즉 메서드 단위로 공통처리 필요 -> AOP
Url 단위 공통처리 필요 + 웹 관련 공통 처리 -> 인터셉터
LoginCheckInterceptor 이다. HandlerInterceptor 를 구현하고, 디스패쳐 서블릿이 각 핸들러를 호출할 때만 검사를 수행하면 되므로 PreHandle 만 오버라이딩 하였다.
reguest.getSession 으로 요청의 HttpSession 객체를 받아온다. 그 후 해당 클라이언트의 session 이 아직 없거나, 로그인 성공시 생기는 "loginUser" 속성이 해당 세션에 없다면 login 화면으로 redirect 시키고 return false로 종료시킨다. 요청 requestUri 를 그대로 가져와서 나중에 로그인 성공시 해당 Uri로 redirect 시켜주도록 하였다.
WebMvnConfigurer 를 구현하고 addInterceptors 를 오버라이딩하면서 registry.addInterceptor 메서드로 인터셉터를 등록한다. order 로 인터셉터의 우선순위를. addPathPatterns 로 인터셉터를 적용시킬 요청의 Url을. excludePatterns 로 인터셉터 적용을 제외할 요청의 Url 을 정할 수 있다. 로그인, 회원가입, css, /error 를 제외시켰다. /error 는 에러시 BasicErrorController 로 재요청을 하기 위해 사용되는 url이다.
다른 URL 입력시 인터셉터에 의해 로그인창으로 redirect 된다.