interceptor

이경현·2024년 11월 6일

인터셉터 :

jsp 의 include file 와 비슷
컨트롤러의 핸들러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 일종의 필터

해당 단어의 의미와 같이 사용자 요청에 의해 서버에 들어온 Request 객체를 컨트롤러의 핸들러(사용자가 요청한 url에 따라 실행되어야 할 메서드, 이하 핸들러)로 도달하기전에 낚아채서 개발자가 원하는 추가적인 작업을 한후 핸들러로 보낼수 있도록 해주는것이 인터셉터 이다.

인터셉터를 사용하는 이유 :

개발자는 특정 controller 의 핸들러가 실행되기 전이나 후에 추가적인 작업을 원할 때 intercptor 를 사용한다 (로그인체크, 권한체크 등)

권한 체크 예를 통해서 개발자가 인터셉터의 어떠한 이점때문에 사용하기를 원하는지 살펴보겠다.

개발자가 관리자 계정만이 실행할수 있는 Controller 핸들러를 작성한다고 가정하겠다.

개발자는 오직 관리자 계정만 실행할수 있도록 하기 위해 핸들러에 접근하는 사용자가 관리자 인지 확인하는

세션 체크 코드를 각 핸들러에 작성해줘야한다.

작성해주어야 할 핸들러수가 적다면 문제가 되지않는다. 하지만 적용해야할 핸들러가 수천개가 된다면 어떻게될까?
크게 두가지 문제가 생긴다.
1) 메모리 낭비, 서버의 부하가 늘어난다. 적용해야할 핸들러만 수만큼 세션체크 코드를 작성함으로써 반복되는 코드들이 매우 많아지기 때문이다.
2) 코드의 누락에 대한 걱정이다. 사람이 작성을 하는것이기 때문에 누락과 같은 실수가 발생할수 밖에없다.
만약 회원정보에 접근하는 핸들러가 세션체크가 누락되어서 관리자 인지 확인을 안한다면, 자격이 없는 사용자가

접근할수 있게되어 보안적으로 큰 문제를 가지게 된다.

이러한 문제점을 줄이기 위한 수단으로, 개발자는 인터셉터를 사용할수 있다.

인터셉터를 사용하게 되면 개발자는 핸들러 수 만큼 작성했던 세션 체크 코드를 인터셉터 클래스에 한번만 작성하면된다. 이로 인해 코드의 량이 현저히 줄기 대문에 메모리 낭비를 줄일수 있다.

그리고 인터셉터 적용의 유무 기준이 되는 url을 servlet-context.xml에 설정해주게 되면 스프링에서 일괄적으로

해당 url 경로의 핸들러에 인터셉터를 적용해주기 때문에 누락에 대한 위험이 상당히 줄게된다.

인터셉터 구현수단

  1. 스프링에서 제공하는 org.springframework.web.servlet.HandlerInterceptor 인터페이스를 구현
  2. org.springframework.web.servlet.handler.HandlerInterceptorAdapter 추상클래스를 오버라이딩 해서 자신만의 인터셉터를 만들수 있다. HandlerInterceptorAdapter 추상클래스 경우 HandlerInterceptor 인터페이스를 상속받아 구현되었다.

인터셉터는 3가지 종류의 핸들러를 가지고 있다

1) preHandle()

컨트롤러가 호출되기 전에 실행됨
컨트롤러가 실행 이전에 처리해야 할 작업이 있는경우 혹은 요청정보를 가공하거나 추가하는경우 사용
실행되어야 할 '핸들러'에 대한 정보를 인자값으로 받기때문에 '서블릿 필터'에 비해 세밀하게 로직을 구성할수 있음
리턴값이 boolean이다. 리턴이 true 일경우 preHandle() 실행후 핸들러에 접근한다. false일경우 작업을 중단하기 때문에 컨트롤러와 남은 인터셉터가 실행되지않는다.

2) postHandle()

핸들러가 실행은 완료 되었지만 아직 View가 생성되기 이전에 호출된다.
ModelAndView 타입의 정보가 인자값으로 받는다. 따라서 Controller에서 View 정보를 전달하기 위해 작업한
Model 객체의 정보를 참조하거나 조작할수 있다.
preHandle() 에서 리턴값이 fasle인경우 실행되지않음.
적용중인 인터셉터가 여러개 인경우, preHandle()는 역순으로 호출된다.
비동기적 요청처리 시에는 처리되지않음.

3) afterCompletion()

모든 View에서 최종 결과를 생성하는 일을 포함한 모든 작업이 완료된 후에 실행된다.
요청 처리중에 사용한 리소스를 반환해주기 적당한 메서드 이다.
preHandle() 에서 리턴값이 false인경우 실행되지 않는다.
적용중인 인터셉터가 여러개인경우 preHandle()는 역순으로 호출된다.
비동기적 요청 처리시에 호출되지않음.

인터셉터 동작 위치 및 순서

  • 사용자는 서버에 자신이 원하는 작업을 요청하기 위해 url을 통해 Request 객체를 보낸다
  • DispatcherServlet 은 해당 Request 객체를 받아서 분석한 뒤 '핸들러 매핑'에게 사용자의 요청을 처리할 핸들러를 찾으라고 요청한다
  • 그 결과로 핸들러 실행체인 (HandlerExectuonChanin)이 동작한다 이 핸들러 실행체인은 하나 이상의 핸들러 인터셉터를 거쳐서 컨트롤러가 실행될 수 있도록 구성되어 있다

(핸들러 인터셉터를 등록하지 않았다면, 곧바로 컨트롤러가 실행된다. 반대로 하나이상의 인터셉터가 지정되어 있다면 지정된 순서에 따라서 인터셉터를 거쳐서 컨트롤러를 실행한다)

구현방법

스프링 프레임워크에서 인터셉터를 적용하기 위한 큰틀은 아래와 같다.

1) HandlerInterceptor 혹은 HandlerInterceptorAdater 를 상속받아서 자신만의 Interceptor 클래스를 생성한다.

2) servlet-context.xml에 우리가 작성한 Interceptor 클래스를 빈(bean)으로 등록해주고, Interceptor를 적용할 url을 작성

회원 목록 보여주기
인터셉터로 로그인 했는지 확인
인터셉터로 인증확인

로그인 확인 하는 인터셉터 만들기

src/main/java 아래에
interceptor 패키지 생성
interceptor 패키지 안에 원하는 클래스 생성
클래스 뒤에 extends HandlerInterceptorAdapter 넣고 import 해주기
HandlerInterceptorAdapter ctrl 누른상태로 클릭하고 handler 복사해오기 (pre/post handler)

접속하기 전에 인터셉트 기능사용하는 것 > preHandler
preHandler 안에 HttpSession session = request.getSession(); 넣어서 세션값 저장하기

if 문으로 회원번호 가 있는지 없는지 확인한다
세션값으로 가져온 midx 가 null 값이 아니면
그 세션값을 일단 다 지워라 >>

if(session.getAttribute("midx") != null) {
session.removeAttribute("midx"); 회원번호 지우고
session.removeAttribute("memberId"); 회원 아이디 지우고
session.removeAttribute("memberName"); 회원 이름 지워
session.invalidate(); // session.invalidate(); =>완전 초기화 시킨다
}
return true;

접속한 다음에 인터셉트 기능 사용하는 것 >>
그다음에 postHandler 에는 접속한 후에 가로채서 동작할 것들 담기
접속한 후에 가로채기 > 정보 담기 !!
model 객체에 저장할 정보를 담을 거임
String 원하는 값 = modelAndView.getModel().get("원하는 값").toString(문자열로 바꿔주고); > 문자열 변수에 담기

다 원하는 변수에담고 나면 modelAndView.getModel().clear(); > 파라미터 모델 값을 지워준다

HttpSession session = request.getSession(); >으로 세션값 가져와서 담기
if 문으로 회원번호가 없으면 ?
if(midx != null) {
session.setAttribute("midx", midx);
session.setAttribute("memberId", memberId);
session.setAttribute("memberName", memberName);

	}

session.setAttribute("담을값", 담을값); 으로 세션 값저장해주기

0개의 댓글