From 6f776ed72a3432fb361c1223c45912b0221b3616 Mon Sep 17 00:00:00 2001 From: Rinjae Date: Wed, 24 Jun 2026 16:52:09 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80:=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=20=EB=AC=B4=ED=9A=A8=ED=99=94=20=EC=A0=84=20DB=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EB=A1=9C=EA=B9=85=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../portal/config/PortalConfigSecurity.java | 3 +++ .../config/PortalLogoutSuccessHandler.java | 24 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/eactive/apim/portal/config/PortalConfigSecurity.java b/src/main/java/com/eactive/apim/portal/config/PortalConfigSecurity.java index bade8b2..d878ede 100644 --- a/src/main/java/com/eactive/apim/portal/config/PortalConfigSecurity.java +++ b/src/main/java/com/eactive/apim/portal/config/PortalConfigSecurity.java @@ -97,6 +97,9 @@ public class PortalConfigSecurity { .successHandler(authenticationSuccessHandler)) .logout(logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET")) + // LogoutHandler 는 기본 SecurityContextLogoutHandler(세션 무효화)보다 먼저 실행된다. + // 세션이 살아있는 이 시점에 DB 세션 레코드를 정리해야 중복세션 오탐("이미 접속중")을 막는다. + .addLogoutHandler(logoutSuccessHandler) .logoutSuccessHandler(logoutSuccessHandler)) .csrf(csrf -> csrf .csrfTokenRepository(csrfTokenRepository) diff --git a/src/main/java/com/eactive/apim/portal/config/PortalLogoutSuccessHandler.java b/src/main/java/com/eactive/apim/portal/config/PortalLogoutSuccessHandler.java index 8ff056a..d06b7c3 100644 --- a/src/main/java/com/eactive/apim/portal/config/PortalLogoutSuccessHandler.java +++ b/src/main/java/com/eactive/apim/portal/config/PortalLogoutSuccessHandler.java @@ -6,6 +6,7 @@ import com.eactive.apim.portal.common.util.StringRepeatUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; @@ -19,10 +20,15 @@ import java.time.format.DateTimeFormatter; import java.util.Enumeration; /** - * 로그아웃 성공 시 세션 정보를 로깅하는 핸들러 + * 로그아웃 처리 핸들러. + * + *

DB 세션 레코드 정리와 로깅은 {@link LogoutHandler#logout}에서 수행한다. 이 시점은 기본 + * {@code SecurityContextLogoutHandler}가 HTTP 세션을 무효화하기 이라 세션이 유효하다. + * (성공 핸들러 {@link #onLogoutSuccess}는 무효화 에 실행되어 {@code getSession(false)}가 + * null 이 되므로, 거기서 정리하면 DB 행이 남아 재로그인 시 "이미 접속중" 오탐이 발생한다.) */ @Component -public class PortalLogoutSuccessHandler implements LogoutSuccessHandler { +public class PortalLogoutSuccessHandler implements LogoutHandler, LogoutSuccessHandler { private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session"); private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); @@ -33,9 +39,12 @@ public class PortalLogoutSuccessHandler implements LogoutSuccessHandler { this.userSessionService = userSessionService; } + /** + * 세션 무효화 전에 실행되어 DB 세션 레코드를 정리하고 로그아웃 정보를 로깅한다. + */ @Override - public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws IOException, ServletException { + public void logout(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) { HttpSession session = request.getSession(false); if (session != null) { @@ -107,7 +116,14 @@ public class PortalLogoutSuccessHandler implements LogoutSuccessHandler { sessionLogger.info(logMessage.toString()); } + } + /** + * 로그아웃(세션 무효화) 완료 후 메인으로 리다이렉트한다. + */ + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { response.sendRedirect(request.getContextPath() + "/"); } }