요르딩딩
Spring - Interceptor 본문
이번시간에는 intercept를 활용한 Session체크 공통부분을 구현해 보았습니다.
인증 확인은 크게 Filter와 Interceptor를 활용하여, controller에 접근하기 전에 전처리할 수 있도록 공통화를 많이 한다고 합니다.
저희 회사는 세션관련 객체를 controller 또는 service단에서 처리를 하고 있었습니다. 그 이유는 회사 방침이 그렇게 적용되고 있었기 때문입니다. 그런데 이렇게 하니 모든 API를 만들때마다 꽤나 긴 공통코드를 여러번 반복해야하고, Controller 또는 Service단까지 들어와야 인증체크를 할 수 있기에 그다지 좋은 방식은 아니라고 생각합니다.
그리하여, filter와 interceptor에서 공통으로 전처리를 하면 좋을거 같다는 생각을 했습니다.
처음에는 filter가 더 앞단으로, filter에 적용하려하였으나, 회사 프레임워크를 사용해야하는 이슈가 있었습니다.
회사 프레임워크를 사용하지 않고, 개발할시 여러가지 이슈가 발생할 수 있고, 회사내부 세션체크 정책이 바뀌면 일일히 바꿔줘야하는 이슈가 있어, 최대한 회사 프레임워크를 사용하는 방향으로 개발하기로 했습니다.
(filter는 dispatcher-servlet의 앞단에서 실행하기 때문에, 스프링영역 밖이라 컨테이너에 등록된 빈을 사용할 수 없는 이슈가 발생)
그러므로, dispatcher-servlet 다음의 Spring영영에 위치한 interceptor를 사용했습니다.
interceptor는 Spring영역으로 빈으로 등록된 객체를 사용할 수 있기에 보다 적합하다고 생각했기 때문입니다.
(실행순서 : Client > Filter > Dispatcher-servlet > Interceptor > Controller > Service > ~~~)
[Session 클래스]
세션객체를 담을 클래스 선언
package com.~~.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Session {
private long userNo;
private long companyNo;
private String portalId;
private String userName;
}
[interceptor 구현부]
회사내부 설정대로 세션을 체크한뒤, 새로운 세션객체에 담아서 controller단으로 전달했습니다.
새로운 객체를 사용하는 이유는 프레임워크에 있는 객체는 불필요 정보까지 담겨있기에 필요한 것만 따로 저장하여 전달했습니다.
package com.~~.interceptor;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.DUZEX.common.model.RuSession;
import com.DUZEX.Ru.common.service.SessionService;
import com.DUZEX.Ru.~~.dto.Session;
public class sessionInterceptor extends HandlerInterceptorAdapter {
protected Logger logger = LogManager.getLogger(this.getClass());
@SuppressWarnings("unused")
private final Properties RuProperties;
private final SessionService sessionService;
@Autowired
sessionInterceptor(Properties RuProperties, SessionService sessionService) {
this.RuProperties = RuProperties;
this.sessionService = sessionService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("=================== START ===================");
System.out.println(" Request URI \t: " + request.getRequestURI());
// 내부 세션 체크 정책
RuSession RuSession = sessionService.getSession();
if (RuSession == null || RuSession.getUser_no() == null || RuSession.getCompany_no() == null) {
System.out.println("=================== No Session ===================");
return false;
}
Session session = new Session();
session.setUserNo(RuSession.getUser_no());
session.setCompanyNo(RuSession.getCompany_no());
session.setPortalId(RuSession.getPortal_id());
session.setUserName(RuSession.getUser_name());
// DUZEX은 RequestUtil.paramToHashMap에서 주소값을 그냥 스트링으로 바꿔버림...
request.setAttribute("session", session);
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("=================== END ===================\n");
super.postHandle(request, response, handler, modelAndView);
}
}
[interceptor 설정 - context-interceptor.xml]
모든 경로로 들어온거 적용
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.~~.interceptor.sessionInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
web.xml 의 아래 부분이 context-interceptor.xml을 읽습니다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/context-*.xml</param-value>
</context-param>
[controller]
interceptor에서 받아온 객체를 param에 넣어 service단으로 넘깁니다.
( -> 기존의 방식을 최대한 고수하기 위해 사용)
/**
* 예시 Controller
*/
@GetMapping("test/test1")
public Entity<?> select(HttpServletRequest request) throws Exception {
//모두 String으로 변환, Session의 경우 주소가 String으로 변환되는 이슈
HashMap<String, Object> param = RequestUtil.paramToHashMap(request);
// 세션객체 service단으로 넘기기
Session session = (Session) request.getAttribute("session");
param.put("session",session);
RuResult result = service.selectInfo(param);
return ResponseUtil.response(result);
}
[Service]
//호츌
Session session = (Session) param.get("session");
//사용
System.out.println(session);
System.out.println(session.getUserNo());
System.out.println(session.getCompanyNo());
'[Web] > [Spring]' 카테고리의 다른 글
@ExceptionHandler, @Valid (0) | 2022.12.27 |
---|---|
Spring - Filter (0) | 2022.11.11 |
[Spring] branch 생성 및 적용하는법 (0) | 2022.09.20 |
JUnit 테스트하는 방법 (0) | 2022.09.14 |
DTO를 사용해보자 (0) | 2022.08.12 |