로그아웃 핸들러 추가: 세션 무효화 전 DB 정리 및 로깅 처리
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

This commit is contained in:
Rinjae
2026-06-24 16:52:09 +09:00
parent e242d3ed06
commit 6f776ed72a
2 changed files with 23 additions and 4 deletions
@@ -97,6 +97,9 @@ public class PortalConfigSecurity {
.successHandler(authenticationSuccessHandler)) .successHandler(authenticationSuccessHandler))
.logout(logout -> logout .logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET")) .logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET"))
// LogoutHandler 는 기본 SecurityContextLogoutHandler(세션 무효화)보다 먼저 실행된다.
// 세션이 살아있는 이 시점에 DB 세션 레코드를 정리해야 중복세션 오탐("이미 접속중")을 막는다.
.addLogoutHandler(logoutSuccessHandler)
.logoutSuccessHandler(logoutSuccessHandler)) .logoutSuccessHandler(logoutSuccessHandler))
.csrf(csrf -> csrf .csrf(csrf -> csrf
.csrfTokenRepository(csrfTokenRepository) .csrfTokenRepository(csrfTokenRepository)
@@ -6,6 +6,7 @@ import com.eactive.apim.portal.common.util.StringRepeatUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication; 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.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -19,10 +20,15 @@ import java.time.format.DateTimeFormatter;
import java.util.Enumeration; import java.util.Enumeration;
/** /**
* 로그아웃 성공 시 세션 정보를 로깅하는 핸들러 * 로그아웃 처리 핸들러.
*
* <p>DB 세션 레코드 정리와 로깅은 {@link LogoutHandler#logout}에서 수행한다. 이 시점은 기본
* {@code SecurityContextLogoutHandler}가 HTTP 세션을 무효화하기 <b>전</b>이라 세션이 유효하다.
* (성공 핸들러 {@link #onLogoutSuccess}는 무효화 <b>후</b>에 실행되어 {@code getSession(false)}가
* null 이 되므로, 거기서 정리하면 DB 행이 남아 재로그인 시 "이미 접속중" 오탐이 발생한다.)
*/ */
@Component @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 Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 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; this.userSessionService = userSessionService;
} }
/**
* 세션 무효화 전에 실행되어 DB 세션 레코드를 정리하고 로그아웃 정보를 로깅한다.
*/
@Override @Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException { Authentication authentication) {
HttpSession session = request.getSession(false); HttpSession session = request.getSession(false);
if (session != null) { if (session != null) {
@@ -107,7 +116,14 @@ public class PortalLogoutSuccessHandler implements LogoutSuccessHandler {
sessionLogger.info(logMessage.toString()); sessionLogger.info(logMessage.toString());
} }
}
/**
* 로그아웃(세션 무효화) 완료 후 메인으로 리다이렉트한다.
*/
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.sendRedirect(request.getContextPath() + "/"); response.sendRedirect(request.getContextPath() + "/");
} }
} }