Skip to main content

설정방법

애플리케이션에서 사용 방법

Infinispan HotRod 모드

  • pom.xml에 dependency 추가
<dependency>
<groupId>com.opennaru.khan</groupId>
<artifactId>khan-session-hotrod</artifactId>
<version>5.1.0</version>
</dependency>
  • 필터 클래스명

com.opennaru.khan.session.filter.InfinispanHotRodSessionFilter

애플리케이션 설정 방법

web.xml의 필터 설정 추가

<?xml version="1.0" encoding="UTF-8"?>
{/*
~ Opennaru, Inc. http://www.opennaru.com/
~
~ Copyright (C) 2014 Opennaru, Inc. and/or its affiliates.
~ All rights reserved by Opennaru, Inc.
*/}
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="session1" version="2.5">

<display-name>Test</display-name>
<description>Test App</description>
{/* <distributable/> */}
<filter>
<filter-name>KhanSessionFilter</filter-name>
{/* Hotrod Mode */}
<init-param>
<param-name>configFile</param-name>
<param-value>${OPENMARU_CONFIG_FILE:hotrod.properties}</param-value>
</init-param>
<init-param>
<param-name>infinispanCache</param-name>
<param-value>${OPENMARU_INFINISPAN_CACHE:OPENMARU_SESSION}</param-value>
</init-param>
<init-param>
<param-name>infinispanLoginCache</param-name>
<param-value>${OPENMARU_INFINISPAN_LOGIN_CACHE:OPENMARU_SESSION_LOGIN}</param-value>
</init-param>
<init-param>
<param-name>sessionId</param-name>
<param-value>__KSMSID__</param-value>
</init-param>
<init-param>
<param-name>domain</param-name>
<param-value></param-value>
</init-param>
<init-param>
<param-name>path</param-name>
<param-value>/test1</param-value> {/* 서로 다른 WebApp간 세션 공유하려면 '/' 으로 설정 */}
</init-param>
<init-param>
<param-name>secure</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>httpOnly</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionTimeout</param-name>
<param-value>30</param-value>
</init-param>
<init-param>
<param-name>excludeRegExp</param-name>
<param-value>/.+\.(html|jpg|jpeg|png|gif|js|css|swf)</param-value>
</init-param>
<init-param>
<param-name>allowDuplicateLogin</param-name> {/* 중복 로그인을 허용하려면 true로 설정 */}
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>duplicateLoginPolicy</param-name> {/* 중복 로그인 정책: none, legacy, custom */}
<param-value>none</param-value>
</init-param>
<init-param>
<param-name>invalidateDuplicateLogin</param-name> {/* false 로 설정 하면 내부적으로 invalidate를 호출하지 않음(중복 여부 API 로 체크 후 직접 invalidate API 호출) */}
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>logoutUrl</param-name> {/* 중복 로그인시 logout URL 설정 */}
<param-value>/logout.jsp</param-value>
</init-param>
<init-param>
<param-name>enableImmediateSave</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>KhanSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>com.opennaru.khan.session.listener.SessionListener</listener-class>
</listener>

SpringBoot 사용시 설정방법

SpringBoot에서 XML을 사용하지 않고 Java 코드 기반으로 설정하는 환경에서는 아래와 같이 필터 설정 코드를 추가하여 설정할 수 있다.

@Configuration
public class OpenmaruFilterConfiguration implements WebMvcConfigurer {

@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new InfinispanHotRodSessionFilter());
registrationBean.setOrder(Integer.MIN_VALUE);

registrationBean.addInitParameter(Constants.INFINISPAN_CONFIGFILE_KEY, "hotrod.properties");
registrationBean.addInitParameter(Constants.INFINISPAN_CACHE_KEY, "KHAN_SESSION");
registrationBean.addInitParameter(Constants.INFINISPAN_LOGIN_CACHE_KEY, "KHAN_SESSION_LOGIN");
registrationBean.addInitParameter(Constants.SESSION_ID, "__KSMSID__");
registrationBean.addInitParameter(Constants.DOMAIN, "");
registrationBean.addInitParameter(Constants.PATH, "/");
registrationBean.addInitParameter(Constants.SECURE, "false");
registrationBean.addInitParameter(Constants.HTTP_ONLY, "false");
registrationBean.addInitParameter(Constants.SESSION_TIMEOUT, "30"); // minute
registrationBean.addInitParameter(Constants.SESSION_SAVE_DELAY, "5");
registrationBean.addInitParameter(Constants.EXCLUDE_REG_EXP, "/.+\\.(html|jpg|jpeg|png|gif|js|css|swf)");
registrationBean.addInitParameter(Constants.ALLOW_DUPLICATE_LOGIN, "true");
registrationBean.addInitParameter(Constants.DUPLICATE_LOGIN_POLICY, "none"); // none, legacy, custom
registrationBean.addInitParameter(Constants.DUPLICATE_LOGIN_EXCLUSTION_TYPE, "");
registrationBean.addInitParameter(Constants.INVALIDATE_DUPLICATE_LOGIN, "true");
registrationBean.addInitParameter(Constants.LOGOUT_URL, "");
registrationBean.addInitParameter(Constants.ENABLE_IMMEDIATED_SAVE, "true");
registrationBean.addInitParameter(Constants.ENABLE_STATISTICS, "true");
registrationBean.addInitParameter(Constants.ENABLE_MEMORY_STATISTICS, "false");
registrationBean.addInitParameter(Constants.LICENSE_KEY,
"#### LICENSE KEY ###\n" +
"> REQUEST sales@openmaru.io"
);

registrationBean.setUrlPatterns(Arrays.asList("/*"));
registrationBean.setDispatcherTypes(DispatcherType.ERROR, DispatcherType.INCLUDE, DispatcherType.FORWARD, DispatcherType.REQUEST);
return registrationBean;
}

@Bean
public HttpSessionListener httpSessionListener() {
SessionListener sessionListener = new SessionListener();
System.out.println("SessionListener started.");
return sessionListener;
}
}

키는 순서대로 xml, 환경변수, jvm 속성 설정 시 값

설명기본값
configFile
KSM_CONFIG_FILE
ksm.config.file
설정파일
JVM 환경변수: OPENMARU_CONFIG_FILE
hotrod.properties
infinispanCache
KSM_INFINISPAN_CACHE
ksm.infinispan.cache
세션 메타 저장소OPENMARU_SESSION
infinispanLoginCache
KSM_INFINISPPAN_LOGIN_CACHE
ksm.infinispan.login.cache
세션 데이터 저장소OPENMARU_SESSION_LOGIN
sessionId
KSM_SESSION_ID
ksm.session.id
세션 키(JSESSIONID를 대체하여 사용)KSMSID
domain
KSM_DOMAIN
ksm.domain
세션을 공유할 도메인
멀티 도메인의 경우 subdomain만 다른 경우 공유 가능
ex) login.openmaru.io, www.openmaru.io
path
KSM_PATH
ksm.path
공유할 Context
서로 다른 WebApp간 세션 공유하려면 '/' 으로 설정
/
secure
KSM_SECURE
ksm.secure
Cookie Secure 옵션false
httpOnly
KSM_HTTP_ONLY
ksm.http.only
Cookie httpOnly 옵션false
sameSite
KSM_SAME_SITE
ksm.same.site
Cookie sameSite 옵션
sessionTimeout
KSM_SESSION_TIMEOUT
ksm.session.timeout
세션 타임아웃(분)30
excludeRegExp
KSM_EXCLUDE_REG_EXP
ksm.exclude.reg.exp
세션 호출 제외 확장자/.+\.(html|jpg|jpeg|png|gif|js|css|swf)
allowDuplicateLogin
KSM_ALLOW_DUPLICATE_LOGIN
ksm.allow.duplicate.login
중복 로그인을 허용하려면 true로 설정
ex) SessionLoginManager.getInstance().login(request, [ID])
true
duplicateLoginPolicy
KSM_DUPLICATE_LOGIN_POLICY
ksm.duplicate.login.policy
중복 로그인 정책 설정
none: 아무런 동작 안함
legacy: 이전 DUPLICATED 정보 리턴으로 관리(이전에 로그인된 사용자 logout)
custom: 중복 로그인된 session list로 관리(이전, 이후 모두 가능)
none
invalidateDuplicateLogin
KSM_INVALIDATE_DUPLICATE_LOGIN
ksm.invalidate.duplicate.login
중복 로그인 감지 시 기존 세션 무효화 여부
true: 중복 로그인 감지 시 기존 세션을 자동으로 무효화
false: 중복 로그인 감지 시 세션을 유지하고 로그아웃 URL로만 리다이렉트
false
duplicateLoginExclustionType
KSM_DUPLICATE_LOGIN_EXCLUTION_TYPE
ksm.duplicate.login.exclution.type
중복로그인 제외 사용자 유형
여러개 일 경우 콤마로 구분
ex) SessionLoginManager.getInstance().login(request, [ID], [TYPE])
logoutUrl
KSM_LOGOUT_URL
ksm.logout.url
중복 로그인 감지 시 리다이렉트할 로그아웃 URL
• 설정된 경우: 중복 로그인 감지 시 해당 URL로 리다이렉트
• 빈 문자열인 경우: 리다이렉트하지 않음
(빈 문자열)
enableImmediateSave
KSM_ENABLE_IMMEDIATE_SAVE
ksm.enable.immediate.save
enableImmediateSave값을 true로 설정하면 setAttribute()가 호출될때 즉시 스토어에 저장함false

Hotrod 클라이언트/서버 모드를 사용할 때 설정

hotrod.properties 파일에서 Infinispan 서버의 IP:PORT 설정한다. JBoss Data Grid(Infinispan) Server는 OPENMARU Installer를 이용하여 자동 설치할 수 있습니다.

infinispan.client.hotrod.server_list = 192.168.0.11:11222

메모리 모니터링을 위한 설정

JBoss EAP 6.x는 아래 설정이 필요함(다른 WAS는 필요 없음)

export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,org.github.jamm"

javaagent 옵션 설정

export JAVA_OPTS=" $JAVA_OPTS -javaagent:/PATH_TO_JAMM_JAR/jamm-0.2.5.jar"

메모리 모니터링 활성화

web.xml의 필터 설정에서 메모리 모니터링을 활성화한다.

<init-param>
<param-name>enableMemoryStatistics</param-name>
<param-value>true</param-value>
</init-param>

중복 로그인 방지 기능 설정

중복로그인 방지 기능을 사용하려면 로그인, 로그아웃시 OPENMARU CLUSTER가 제공하는 API를 사용하여 다음과 같이 로그인/로그아웃 코드를 추가하여야 한다.

로그인 성공시 아래 코드 사용

SessionLoginManager.getInstance().login(request, [USER_ID]);

로그아웃 및 세션 무효화

invalidateDuplicateLogin=true 인 경우 (자동 로그아웃 처리)

invalidateDuplicateLogintrue로 설정되어 있으면 중복 로그인 시 자동으로 로그아웃 처리를 수행한다.

동작:

  1. 중복 로그인 감지 시 SessionLoginManager.getInstance().logout() 자동 호출
  2. 세션 무효화(session.invalidate())까지 자동 처리
  3. 설정된 로그아웃 URL로 자동 리다이렉트 (logoutUrl 설정 시)

따라서 애플리케이션 코드에서 별도의 로그아웃 처리 코드를 작성할 필요가 없다.

invalidateDuplicateLogin=false 인 경우 (수동 로그아웃 처리)

invalidateDuplicateLoginfalse로 설정하면 중복 로그인이 감지되어도 시스템에서 자동으로 세션을 무효화하지 않는다. 중복 로그인을 직접 체크 및 invalidate 해야 할 경우 활용할 수 있다.

web.xml 설정

web.xml 필터 설정에 invalidateDuplicateLogin을 false로 설정한다.

<init-param>
<param-name>invalidateDuplicateLogin</param-name>
<param-value>false</param-value>
</init-param>

invalidateDuplicateLogin=false 일 때의 동작

  • 중복 로그인 감지 시 기존 세션을 무효화하지 않음
  • 세션 정보를 세션 저장소에서 제거하지 않음 (loginRemove 호출 안함)
  • SessionLoginManager.logout() 호출하지 않음
  • session.invalidate() 호출하지 않음
  • 설정된 logoutUrl로 리다이렉트만 수행 (logoutUrl이 설정된 경우)

수동으로 로그아웃 처리를 해야 하는 경우 다음 코드를 사용한다.

SessionLoginManager.getInstance().logout(request);

사용자 명시적 로그아웃 처리

사용자가 직접 로그아웃 버튼을 클릭하는 경우 다음과 같이 처리한다.

// 로그아웃 처리 예제
public void doLogout(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
// OPENMARU Cluster 로그아웃 처리
SessionLoginManager.getInstance().logout(request);

// 세션 무효화
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}

// 로그인 페이지로 리다이렉트
response.sendRedirect("/login.jsp");

} catch (Exception e) {
// 로그아웃 실패 시 에러 처리
log.error("로그아웃 처리 중 오류 발생", e);
throw e;
}
}
  • 사용자 명시적 로그아웃 시에는 반드시 SessionLoginManager.getInstance().logout(request) 호출 후 session.invalidate()를 호출해야 한다.
  • invalidateDuplicateLogin=true로 설정하면 중복 로그인 시 자동 처리되므로 별도 코드가 필요하지 않다.

중복 로그인 관련 활용 API

중복 로그인 체크

Java 코드에서 중복로그인 여부를 isDuplicated 메소드로 확인할 수 있다.

boolean isDuplicated = SessionLoginManager.getInstance().isDuplicated(request);

로그인한 사용자 정보

Java 코드에서 loggedInUserId 메소드로 로그인한 사용자 ID를 얻을 수 있다.

String loginUserId = SessionLoginManager.getInstance().loggedInUserId(request);

로그인 사용자 리스트

Java 코드에서 로그인한 사용자 리스트를 얻을 수 있다.

List<LoginUser> loginUsers = SessionLoginManager.getInstance().getLoginUsers();

로그인 사용자 Session Attributes

로그인한 사용자의 세션 속성을 getSessionAttributes API로 가져올 수 있다.

Map<String, Object> sessionAttributes = SessionLoginManager.getInstance().getSessionAttributes(sessionId);

특정 로그인 사용자 강제 로그아웃

logout API를 이용하면 특정 사용자를 강제 로그아웃 시킬 수 있다. 이때, 데이터는 삭제하지 않고 중복 로그인이 됐다고 처리한다.

SessionLoginManager.getInstance().logout(loginId, sessionId);

세션 스토어에서 데이터를 직접 가져오는 API

// 세션 ID에 대한 “name” 속성이 Null이 아니면 true를 반환
public boolean isAttributeExistDirect(String sessionId, String
name)
// 세션 ID에 대한 “name” 속성 값을 Object로 반환
public Object getAttributeDirect(String sessionId, String name)

SessionLoginManager.getInstance().getAttributeDirect(session.getId(),
"userId");
SessionLoginManager.getInstance().isAttributeExistDirect(session.getId(),
"userId");

직렬화(Serializable) 필요

세션에 저장하는 객체는 반드시 직렬화되어 있어야 한다.

아래와 같이 User 객체를 세션에 저장하려면, User 클래스는 Serializable을 구현한 객체이어야 한다.

  User user = new User();
...
session.setAttribute("key", user);
public class User implements Serializable {

}

모니터링 활성화 방법

web.xml의 필터 설정에서 MBean 모니터링을 활성화한다.

<init-param>
<param-name>enableStatistics</param-name>
<param-value>true</param-value>
</init-param>