From 72cdb042617e0e5d2bf87297efb2a7435cbd2195 Mon Sep 17 00:00:00 2001 From: eastargh Date: Wed, 29 Apr 2026 15:09:03 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B4=EC=A4=91=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=ED=94=84=EB=9D=BC=ED=8D=BC=ED=8B=B0=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?&=20=EC=9D=B4=EC=A4=91=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=95=84=EC=9B=83=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rms/common/context/MonitoringContext.java | 5 +++ .../interceptor/SessionCheckInterceptor.java | 16 ++++++--- .../eai/rms/common/login/MainController.java | 33 +++++++++++-------- .../login/SessionDestructionListener.java | 4 ++- .../eai/rms/common/login/SessionManager.java | 32 +++++++++++++----- 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/common/context/MonitoringContext.java b/src/main/java/com/eactive/eai/rms/common/context/MonitoringContext.java index 75b99dc..61cf3c1 100644 --- a/src/main/java/com/eactive/eai/rms/common/context/MonitoringContext.java +++ b/src/main/java/com/eactive/eai/rms/common/context/MonitoringContext.java @@ -251,6 +251,11 @@ public interface MonitoringContext { public static final String MENU_RENDER_ADDITIONAL_SERVICES = "menu.render.additional.services"; 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); diff --git a/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java b/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java index 1d9d9d2..5ea17d3 100644 --- a/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java +++ b/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java @@ -1,15 +1,18 @@ package com.eactive.eai.rms.common.interceptor; -import com.eactive.eai.rms.common.login.LoginVo; -import com.eactive.eai.rms.common.login.SessionManager; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.ClassUtils; import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.eactive.eai.rms.common.context.MonitoringContext; +import com.eactive.eai.rms.common.login.LoginVo; +import com.eactive.eai.rms.common.login.SessionManager; public class SessionCheckInterceptor extends HandlerInterceptorAdapter { @@ -20,6 +23,8 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = Logger .getLogger(SessionCheckInterceptor.class); + @Autowired + private MonitoringContext monitoringContext; @Override public boolean preHandle(HttpServletRequest request, @@ -39,6 +44,7 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter { //craft boolean isSkippable = ClassUtils.isAssignable(clazz, InterceptorSkipController.class); + boolean isDualLogin = monitoringContext.getBooleanProperty(MonitoringContext.RMS_DUAL_LOGIN_ENABLED, true); if (isSkippable) { valid = true; @@ -46,7 +52,7 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter { SessionManager.setLoginVo(loginVo); // ThreadLocal에 설정 // 이중 로그인 검사 - if (!SessionManager.isValidSession(request)) { + if (!SessionManager.isValidSession(request, isDualLogin)) { logger.warn("Duplicate login detected for user: " + loginVo.getUserId()); valid = false; } else { diff --git a/src/main/java/com/eactive/eai/rms/common/login/MainController.java b/src/main/java/com/eactive/eai/rms/common/login/MainController.java index f118b33..1471ec8 100644 --- a/src/main/java/com/eactive/eai/rms/common/login/MainController.java +++ b/src/main/java/com/eactive/eai/rms/common/login/MainController.java @@ -391,20 +391,24 @@ public class MainController implements InterceptorSkipController { session.setAttribute("dualLogin", "N"); - // 이중 로그인 확인 - boolean isNewLogin = SessionManager.registerUserSession(request, dto); + boolean isDualLogin = monitoringContext.getBooleanProperty(MonitoringContext.RMS_DUAL_LOGIN_ENABLED, true); - if (!isNewLogin) { - - // 1. - SessionManager.forceRegisterUserSession(request, dto); - session.setAttribute("dualLogin", "Y"); - - // 또는 - // 2. 이중 로그인 에러 표시 - // model.addAttribute("error", "다른 기기에서 이미 로그인 중입니다."); - // return "/"; - } + if (!isDualLogin) { + // 이중 로그인 확인 + boolean isNewLogin = SessionManager.registerUserSession(request, dto); + + if (!isNewLogin) { + + // 1. + SessionManager.forceRegisterUserSession(request, dto); + session.setAttribute("dualLogin", "Y"); + + // 또는 + // 2. 이중 로그인 에러 표시 + // model.addAttribute("error", "다른 기기에서 이미 로그인 중입니다."); + // return "/"; + } + } // 세션에 로그인 정보 저장 request.getSession().setAttribute(CommonConstants.LOGIN, dto); @@ -665,7 +669,8 @@ public class MainController implements InterceptorSkipController { if (loginVo != null) { // 로그인 세션 제거 - SessionManager.removeUserSession(loginVo.getUserId()); + //SessionManager.removeUserSession(loginVo.getUserId()); + SessionManager.removeUserSessionBySessionId(request.getSession().getId()); //2026.04.29 이중로그인 로그아웃 버그 수정 request.getSession().removeAttribute(CommonConstants.LOGIN); diff --git a/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java b/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java index 1fb4d46..929f7ae 100644 --- a/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java +++ b/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java @@ -27,6 +27,7 @@ public class SessionDestructionListener implements HttpSessionListener { HttpSession session = se.getSession(); String userId = (String) session.getAttribute("userId"); + String sessionId = session.getId(); // 로그인 한 사용자의 세션정보 정리 if (userId != null) { @@ -34,7 +35,8 @@ public class SessionDestructionListener implements HttpSessionListener { logger.debug("[SessionListener] 세션만료 감지. 사용자 제거: " + userId); } - SessionManager.removeUserSession(userId); + //SessionManager.removeUserSession(userId); + SessionManager.removeUserSessionBySessionId(sessionId); //2026.04.29 이중로그인 로그아웃 버그 수정 } } catch (Exception e) { diff --git a/src/main/java/com/eactive/eai/rms/common/login/SessionManager.java b/src/main/java/com/eactive/eai/rms/common/login/SessionManager.java index 85d8318..bc690a0 100644 --- a/src/main/java/com/eactive/eai/rms/common/login/SessionManager.java +++ b/src/main/java/com/eactive/eai/rms/common/login/SessionManager.java @@ -4,6 +4,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; +import com.eactive.eai.rms.common.context.MonitoringContext; import com.eactive.eai.rms.common.util.CommonConstants; //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 isDualLogin 이중 로그인 허용여부 * @return true: 유효한 세션, false: 유효하지 않은 세션 */ - public static boolean isValidSession(HttpServletRequest request) { + public static boolean isValidSession(HttpServletRequest request, boolean isDualLogin) { LoginVo loginVo = getLoginVo(request); if (loginVo == null) { return false; } - String userId = loginVo.getUserId(); - String currentSessionId = request.getSession().getId(); - String registeredSessionId = loggedInUsers.get(userId); - - // 등록된 세션이 없거나 현재 세션과 다른 경우 - return registeredSessionId != null && registeredSessionId.equals(currentSessionId); - } + if (isDualLogin) { + return true; + } else { + String userId = loginVo.getUserId(); + String currentSessionId = request.getSession().getId(); + String registeredSessionId = loggedInUsers.get(userId); + + // 등록된 세션이 없거나 현재 세션과 다른 경우 + return registeredSessionId != null && registeredSessionId.equals(currentSessionId); + } + } + + } \ No newline at end of file