이중로그인 프라퍼티 적용 & 이중로그인 로그아웃 버그 수정

This commit is contained in:
eastargh
2026-04-29 15:09:03 +09:00
parent d3601c3991
commit 72cdb04261
5 changed files with 62 additions and 28 deletions
@@ -252,6 +252,11 @@ public interface MonitoringContext {
public static final String KEYSTORE_UPLOAD_PATH = "keystore.upload.path"; public static final String KEYSTORE_UPLOAD_PATH = "keystore.upload.path";
// 이중 로그인 허용여부
public static final String RMS_DUAL_LOGIN_ENABLED = "rms.DUAL_LOGIN_ENABLED";
public abstract String getStringProperty(String propertyName); public abstract String getStringProperty(String propertyName);
public abstract String getStringProperty(String propertyName, String defaultString); public abstract String getStringProperty(String propertyName, String defaultString);
@@ -1,15 +1,18 @@
package com.eactive.eai.rms.common.interceptor; package com.eactive.eai.rms.common.interceptor;
import com.eactive.eai.rms.common.login.LoginVo; import javax.servlet.http.HttpServletRequest;
import com.eactive.eai.rms.common.login.SessionManager; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.ClassUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest; import com.eactive.eai.rms.common.context.MonitoringContext;
import javax.servlet.http.HttpServletResponse; import com.eactive.eai.rms.common.login.LoginVo;
import com.eactive.eai.rms.common.login.SessionManager;
public class SessionCheckInterceptor extends HandlerInterceptorAdapter { public class SessionCheckInterceptor extends HandlerInterceptorAdapter {
@@ -20,6 +23,8 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = Logger private static final Logger logger = Logger
.getLogger(SessionCheckInterceptor.class); .getLogger(SessionCheckInterceptor.class);
@Autowired
private MonitoringContext monitoringContext;
@Override @Override
public boolean preHandle(HttpServletRequest request, public boolean preHandle(HttpServletRequest request,
@@ -39,6 +44,7 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter {
//craft //craft
boolean isSkippable = ClassUtils.isAssignable(clazz, InterceptorSkipController.class); boolean isSkippable = ClassUtils.isAssignable(clazz, InterceptorSkipController.class);
boolean isDualLogin = monitoringContext.getBooleanProperty(MonitoringContext.RMS_DUAL_LOGIN_ENABLED, true);
if (isSkippable) { if (isSkippable) {
valid = true; valid = true;
@@ -46,7 +52,7 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter {
SessionManager.setLoginVo(loginVo); // ThreadLocal에 설정 SessionManager.setLoginVo(loginVo); // ThreadLocal에 설정
// 이중 로그인 검사 // 이중 로그인 검사
if (!SessionManager.isValidSession(request)) { if (!SessionManager.isValidSession(request, isDualLogin)) {
logger.warn("Duplicate login detected for user: " + loginVo.getUserId()); logger.warn("Duplicate login detected for user: " + loginVo.getUserId());
valid = false; valid = false;
} else { } else {
@@ -391,20 +391,24 @@ public class MainController implements InterceptorSkipController {
session.setAttribute("dualLogin", "N"); session.setAttribute("dualLogin", "N");
// 이중 로그인 확인 boolean isDualLogin = monitoringContext.getBooleanProperty(MonitoringContext.RMS_DUAL_LOGIN_ENABLED, true);
boolean isNewLogin = SessionManager.registerUserSession(request, dto);
if (!isNewLogin) { if (!isDualLogin) {
// 이중 로그인 확인
boolean isNewLogin = SessionManager.registerUserSession(request, dto);
// 1. if (!isNewLogin) {
SessionManager.forceRegisterUserSession(request, dto);
session.setAttribute("dualLogin", "Y");
// 또는 // 1.
// 2. 이중 로그인 에러 표시 SessionManager.forceRegisterUserSession(request, dto);
// model.addAttribute("error", "다른 기기에서 이미 로그인 중입니다."); session.setAttribute("dualLogin", "Y");
// return "/";
} // 또는
// 2. 이중 로그인 에러 표시
// model.addAttribute("error", "다른 기기에서 이미 로그인 중입니다.");
// return "/";
}
}
// 세션에 로그인 정보 저장 // 세션에 로그인 정보 저장
request.getSession().setAttribute(CommonConstants.LOGIN, dto); request.getSession().setAttribute(CommonConstants.LOGIN, dto);
@@ -665,7 +669,8 @@ public class MainController implements InterceptorSkipController {
if (loginVo != null) { if (loginVo != null) {
// 로그인 세션 제거 // 로그인 세션 제거
SessionManager.removeUserSession(loginVo.getUserId()); //SessionManager.removeUserSession(loginVo.getUserId());
SessionManager.removeUserSessionBySessionId(request.getSession().getId()); //2026.04.29 이중로그인 로그아웃 버그 수정
request.getSession().removeAttribute(CommonConstants.LOGIN); request.getSession().removeAttribute(CommonConstants.LOGIN);
@@ -27,6 +27,7 @@ public class SessionDestructionListener implements HttpSessionListener {
HttpSession session = se.getSession(); HttpSession session = se.getSession();
String userId = (String) session.getAttribute("userId"); String userId = (String) session.getAttribute("userId");
String sessionId = session.getId();
// 로그인 한 사용자의 세션정보 정리 // 로그인 한 사용자의 세션정보 정리
if (userId != null) { if (userId != null) {
@@ -34,7 +35,8 @@ public class SessionDestructionListener implements HttpSessionListener {
logger.debug("[SessionListener] 세션만료 감지. 사용자 제거: " + userId); logger.debug("[SessionListener] 세션만료 감지. 사용자 제거: " + userId);
} }
SessionManager.removeUserSession(userId); //SessionManager.removeUserSession(userId);
SessionManager.removeUserSessionBySessionId(sessionId); //2026.04.29 이중로그인 로그아웃 버그 수정
} }
} catch (Exception e) { } catch (Exception e) {
@@ -4,6 +4,7 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.util.CommonConstants; import com.eactive.eai.rms.common.util.CommonConstants;
//craft //craft
@@ -206,23 +207,38 @@ public class SessionManager {
} }
} }
/**
* 사용자의 로그인 세션을 제거 (이중로그인 버그 수정용)
* @param sessionId 로그인한 session ID
*/
public static void removeUserSessionBySessionId(String sessionId) {
loggedInUsers.entrySet().removeIf(entry -> sessionId.equals(entry.getValue()));
}
/** /**
* 현재 세션이 유효한 로그인 세션인지 확인 * 현재 세션이 유효한 로그인 세션인지 확인
* @param request HTTP 요청 * @param request HTTP 요청
* @param isDualLogin 이중 로그인 허용여부
* @return true: 유효한 세션, false: 유효하지 않은 세션 * @return true: 유효한 세션, false: 유효하지 않은 세션
*/ */
public static boolean isValidSession(HttpServletRequest request) { public static boolean isValidSession(HttpServletRequest request, boolean isDualLogin) {
LoginVo loginVo = getLoginVo(request); LoginVo loginVo = getLoginVo(request);
if (loginVo == null) { if (loginVo == null) {
return false; return false;
} }
String userId = loginVo.getUserId(); if (isDualLogin) {
String currentSessionId = request.getSession().getId(); return true;
String registeredSessionId = loggedInUsers.get(userId); } else {
String userId = loginVo.getUserId();
String currentSessionId = request.getSession().getId();
String registeredSessionId = loggedInUsers.get(userId);
// 등록된 세션이 없거나 현재 세션과 다른 경우 // 등록된 세션이 없거나 현재 세션과 다른 경우
return registeredSessionId != null && registeredSessionId.equals(currentSessionId); return registeredSessionId != null && registeredSessionId.equals(currentSessionId);
}
} }
} }