설정방법
애플리케이션에서 사용 방법
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 인 경우 (자동 로그아웃 처리)
invalidateDuplicateLogin 이 true로 설정되어 있으면 중복 로그인 시 자동으로 로그아웃 처리를 수행한다.
동작:
- 중복 로그인 감지 시
SessionLoginManager.getInstance().logout()자동 호출 - 세션 무효화(
session.invalidate())까지 자동 처리 - 설정된 로그아웃 URL로 자동 리다이렉트 (logoutUrl 설정 시)
따라서 애플리케이션 코드에서 별도의 로그아웃 처리 코드를 작성할 필요가 없다.
invalidateDuplicateLogin=false 인 경우 (수동 로그아웃 처리)
invalidateDuplicateLogin을 false로 설정하면 중복 로그인이 감지되어도 시스템에서 자동으로 세션을 무효화하지 않는다. 중복 로그인을 직접 체크 및 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>