아키텍처와 함께

블로그 이미지
by gregorio
  • Total hit
  • Today hit
  • Yesterday hit

Spring framework을 적용하는 프로젝트에서 사용자 로그인 검증, URI에 대한 권한 체크를 수행하기 위해 Interceptor를 적용하고 있다.


Interceptor에 대해 인터넷에 많은 예제들이 나와 있지만, 실제 프로젝트에 적용하기 위해서는 프로젝트 환경에 맞게 Customizing이 필요하다.


일반적으로 사용자가 로그인하면 사용자에게 권한이 있는 메뉴를 화면에 표시하여 메뉴를 선택하면 해당 이벤트를 처리하는 방식으로 구현한다.


만약 사용자가 시스템에 대한 권한이 없는 URL를 알고 브라우저의 URL 입력 창에 해당 URL을 입력하면 서비스가 처리는 되는 경우도 발생한다.


이러한 상황에서 요청한 URI에 대해 사용자가 권한을 가지고 있는지 검증하기 위해 Interceptor에 적용하는 방법이다.

  


먼저 URI를 검증하고자 하는 Service와 ServiceImpl을 구현한다.


■ 서비스

 public interface AuthCheckService {

public int selectAuthCheck(Object[] params) throws Exception;


}



■ 서비스 구현

public class AuthCheckServiceImpl extends BaseService implements AuthCheckService {


private JdbcTemplate jdbcTemplate;

private String defaultSql;

private String resultColName;

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

this.jdbcTemplate = jdbcTemplate;

}


public void setDefaultSql(String defaultSql) {

this.defaultSql = defaultSql;

}


public void setResultColName(String resultColName) {

this.resultColName = resultColName;

}


@Override

public int selectAuthCheck(Object[] params) throws Exception {

Map<String, Object> resultMap = jdbcTemplate.queryForMap(defaultSql, params);

return resultMap.get(resultColName) != null ? Integer.parseInt(String.valueOf(resultMap.get(resultColName))) : 0;

}

 


ServiceImp에서는 JdbcTemplate의 queryForMap 메소드를 호출하여 Map으로 결과를 받는다.


ServiceImp에서는 JdbcTemplate, defaultSql, resultColumnName을 bean설정에서 Property로 세팅된다.


ServiceImpl의 Bean  설정은 예제이다.


■ ServiceImp Bean 설정

<bean id="sbJndiResource" class="org.springframework.jndi.JndiObjectFactoryBean">

<property name="jndiName" value="${sb.jndi.datasource.name}" />

<property name="resourceRef" value="true" />

</bean>  


<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

<property name="dataSource" ref="sbJndiResource" />

</bean>

    

 <bean id="authCheckService" class="stis.framework.spring.service.impl.AuthCheckServiceImpl">

<property name="jdbcTemplate" ref="jdbcTemplate" />

<property name="defaultSql" value="#{system['auth.check.sql']}" />

<property name="resultColName" value="cnt" />

</bean>



JdbcTemplate을 사용하기 위해서는 Datasource 설정이 필요하다. 여기서는 JNDI lookup을 통해 WAS에 설정된 Datasource를 찾는다.


defaultSql은 Properties file에 설정되었다. 조회조건에 <, > 가 포함되어 있으면 XML 설정 파일에 정의할 수 없기 때문에 properties 파일에 SQL을 설정한 후 해당 Properties를 참조하도록 하였다.


resultColName은 ServiceImpl에서 Map으로 받은 데이터를 가져오기 위해 필요하다.

즉 SQL의 결과와 동일한 이름을 사용하면 된다.


이제 Interceptor를 개발하기 위한 준비가 되었다.

■ Interceptor 예제

public class SessionInterceptor extends HandlerInterceptorAdapter implements InitializingBean{

private static final Logger LOGGER = LoggerFactory.getLogger(SessionInterceptor.class);

/** Login Check Skip URIs **/

private List<String> skipUris;

/** LOGIN URL **/

private String loginURI;

private SessionVo sessionVo;

private String blockServiceName;

private String authCheckServiceName;

public void setSkipUris(List<String> skipUris) {

this.skipUris = skipUris;

}


@Required

public void setLoginURI(String loginURI) {

this.loginURI = loginURI;

}

@Required

public void setSessionVo(SessionVo sessionVo) {

this.sessionVo = sessionVo;

}



public void setBlockServiceName(String blockServiceName) {

this.blockServiceName = blockServiceName;

}



public void setAuthCheckServiceName(String authCheckServiceName) {

this.authCheckServiceName = authCheckServiceName;

}



/**

* Return boolean

* @param HttpServletRequest

* @param HttpServletResponse

* @paeam Object handler

* @return boolean

* @see 

*/


@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

String requestURI = request.getRequestURI();


long startTime = System.currentTimeMillis();

request.setAttribute("startTime", Long.valueOf(startTime));

request.setAttribute("requestURI", requestURI);

request.setAttribute("clientIP", NetUtil.getClinetIP());

/** Session Vo Check if null create new session Vo **/

boolean isSkipUri = false;

if (!NullUtil.isNull(skipUris)) {

isSkipUri = StringUtil.isMatchPattern(skipUris, requestURI);

}

/** Login Check **/

if (!isSkipUri) {

/** Get session value from HTTP Session **/

sessionVo = SessionUtil.getSession(BaseConstants.DEFAULT_SESSION_NAME);

/** Move to Login Page **/

if (NullUtil.isNull(sessionVo)) {

response.sendRedirect(loginURI);

LOGGER.error("You shoud logon the system to use the system(session is null) :: {}", requestURI);

return super.preHandle(request, response, handler);

}

else {

if (NullUtil.isNull(sessionVo.getUserId())) {

response.sendRedirect(loginURI);

LOGGER.error("You shoud logon the system to use the system(userId is null) :: {}", requestURI);

return super.preHandle(request, response, handler);

}

}

}

if (!isSkipUri) {

/** AuthCheck Service **/

if (!NullUtil.isNull(authCheckServiceName)) {

AuthCheckService authCheckService = BeanUtil.getBean(authCheckServiceName);

String[] params = {sessionVo.getUserId(), requestURI};

int cnt = authCheckService.selectAuthCheck(params);

if (cnt <= 0) {

String errMsg = String.format("You don't have authorization to use this URI [%s]", requestURI);

LOGGER.error(errMsg);

throw new AuthException(errMsg);

}

}

}

/** Check Block Service **/

if (!NullUtil.isNull(blockServiceName)) {

BlockService blockService = BeanUtil.getBean(blockServiceName);

List<String> blockLists = blockService.getBlockList();

if (StringUtil.isMatchPattern(blockLists, requestURI)) {

String errMsg = String.format("The service of [%s] is blocked, please contact system administrator", requestURI);

LOGGER.error(errMsg);

throw new AuthException(errMsg);

}

}

return super.preHandle(request, response, handler);

}


/**

* Return void

* @param HttpServletRequest

* @param HttpServletResponse

* @paeam Object handler

* @return void

* @see

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) throws Exception {


}


/**

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {


String requestURI = request.getAttribute("requestURI").toString();


if (LOGGER.isDebugEnabled()) {

LOGGER.debug("Session Interceptor is called : {}", requestURI);

}

/** If request URI is login or logout, set host name, host address  to session information 

*  When logout, session information is invalidated

* */



long startTime = (Long) request.getAttribute("startTime");

long endTime = System.currentTimeMillis();

LOGGER.info("Request URL::{} Request ClinetIP::{} Response Code::{} Start Time::{} End Time::{}  Elapse Time::{}(ms)",

requestURI, request.getAttribute("clientIP"), response.getStatus(), startTime, endTime, (endTime - startTime));

}



@Override

public void afterPropertiesSet() throws Exception {

}

 


Interceptor에서 Bean이름으로 bean을 찾아서 Bean의 method를 호출한 후 Count를 받아 count가 0보다 작은 경우 Exception을 처리한다.



■Interceptor 설정 예제

<mvc:interceptors>

<mvc:interceptor>

<mvc:mapping path="/**"/>

<bean id="sessionInteceptor" class="stis.framework.spring.interceptor.SessionInterceptor">

<property name="skipUris">

<list>

<value>/sample/login.do</value>

<value>/sample/logout.do</value>

<value>/common/error.do</value>

<value>/rest/*</value>

</list>

</property>

<property name="sessionVo" ref="sessionVo" />

<property name="loginURI" value="/sample/loginPage.do" />

<property name="authCheckServiceName" value="authCheckService" />

</bean>

</mvc:interceptor>

</mvc:interceptors> 


Interceptor 설정 파일에서 authCheckServiceName 값을 ServiceImp 설정의 bean id 를 값으로 전달하였다.


사용자의 URI에 대한 권한 체크하는 SQL은 프로젝트 환경에 따라 다를 수 있기 때문에 여기에서는 SQL은 예외로 한다.



 

'Spring Framrwork' 카테고리의 다른 글

Spring Framework File Upload with Drag and Drop  (0) 2018.03.16
Spring framework XML Marshaller( Jaxb2Marshaller )  (0) 2018.03.09
Google Map javascript API 사용법  (0) 2018.02.07
C3 Bar Chart  (0) 2018.02.05
Spring Batch 모니터링 SQL  (0) 2018.02.03
AND

ARTICLE CATEGORY

분류 전체보기 (56)
Spring Framrwork (33)
Linux (1)
APM (1)
Java (8)
python (0)
ant (1)
chart (1)
OS (1)
tomcat (1)
apache (1)
database (0)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

ARCHIVE

LINK