Add HTTP session logging for authentication events
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package com.eactive.apim.portal.common.util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* HTTP 요청 관련 유틸리티 클래스
|
||||
*/
|
||||
public class HttpRequestUtil {
|
||||
|
||||
private static final String[] IP_HEADER_CANDIDATES = {
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_X_FORWARDED_FOR",
|
||||
"HTTP_X_FORWARDED",
|
||||
"HTTP_X_CLUSTER_CLIENT_IP",
|
||||
"HTTP_CLIENT_IP",
|
||||
"HTTP_FORWARDED_FOR",
|
||||
"HTTP_FORWARDED",
|
||||
"HTTP_VIA",
|
||||
"REMOTE_ADDR",
|
||||
"X-Real-IP"
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy를 통한 접속도 고려하여 실제 클라이언트 IP 주소를 반환
|
||||
*
|
||||
* @param request HttpServletRequest 객체
|
||||
* @return 클라이언트 IP 주소
|
||||
*/
|
||||
public static String getClientIpAddress(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
String ip = null;
|
||||
|
||||
// 헤더들을 순회하면서 IP 주소 찾기
|
||||
for (String header : IP_HEADER_CANDIDATES) {
|
||||
ip = request.getHeader(header);
|
||||
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 헤더에서 IP를 찾지 못한 경우 기본 메서드 사용
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
// X-Forwarded-For 헤더는 여러 IP를 포함할 수 있음 (쉼표로 구분)
|
||||
// 첫 번째 IP가 실제 클라이언트 IP
|
||||
if (ip != null && ip.contains(",")) {
|
||||
ip = ip.split(",")[0].trim();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy를 통한 접속도 고려하여 실제 클라이언트 호스트명을 반환
|
||||
*
|
||||
* @param request HttpServletRequest 객체
|
||||
* @return 클라이언트 호스트명
|
||||
*/
|
||||
public static String getClientHost(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
String host = request.getHeader("X-Forwarded-Host");
|
||||
if (host == null || host.isEmpty() || "unknown".equalsIgnoreCase(host)) {
|
||||
host = request.getRemoteHost();
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청이 Proxy를 통해 들어왔는지 확인
|
||||
*
|
||||
* @param request HttpServletRequest 객체
|
||||
* @return Proxy를 통한 접속이면 true, 아니면 false
|
||||
*/
|
||||
public static boolean isProxied(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String header : IP_HEADER_CANDIDATES) {
|
||||
String value = request.getHeader(header);
|
||||
if (value != null && !value.isEmpty() && !"unknown".equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.eactive.apim.portal.common.util;
|
||||
|
||||
/**
|
||||
* JDK 8 호환성을 위한 문자열 반복 유틸리티
|
||||
*/
|
||||
public class StringRepeatUtil {
|
||||
|
||||
/**
|
||||
* 문자를 지정된 횟수만큼 반복하여 문자열을 생성
|
||||
*
|
||||
* @param ch 반복할 문자
|
||||
* @param count 반복 횟수
|
||||
* @return 반복된 문자열
|
||||
*/
|
||||
public static String repeat(char ch, int count) {
|
||||
if (count <= 0) {
|
||||
return "";
|
||||
}
|
||||
char[] chars = new char[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
chars[i] = ch;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 문자열을 지정된 횟수만큼 반복
|
||||
*
|
||||
* @param str 반복할 문자열
|
||||
* @param count 반복 횟수
|
||||
* @return 반복된 문자열
|
||||
*/
|
||||
public static String repeat(String str, int count) {
|
||||
if (str == null || count <= 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(str.length() * count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.eactive.apim.portal.config;
|
||||
import com.eactive.apim.portal.apps.login.constants.LoginConstants;
|
||||
import com.eactive.apim.portal.apps.user.service.PortalUserLogService;
|
||||
import com.eactive.apim.portal.common.exception.UserNotFoundException;
|
||||
import com.eactive.apim.portal.common.util.HttpRequestUtil;
|
||||
import com.eactive.apim.portal.common.util.StringRepeatUtil;
|
||||
import com.eactive.apim.portal.portaluser.entity.PortalUser;
|
||||
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
@@ -23,6 +25,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Created by Sungpil Hyun
|
||||
@@ -32,6 +36,9 @@ import java.io.IOException;
|
||||
public class PortalAuthenticationFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PortalAuthenticationFailureHandler.class);
|
||||
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 final PortalUserRepository portalUserRepository;
|
||||
private final PortalUserLogService userLogService;
|
||||
private final MessageHandlerService messageHandlerService;
|
||||
@@ -82,10 +89,39 @@ public class PortalAuthenticationFailureHandler implements AuthenticationFailure
|
||||
|
||||
userLogService.logFailure(username, ip, sessionId);
|
||||
|
||||
// 로그인 실패 시 세션 정보 로깅
|
||||
logLoginFailure(request, username, exception);
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
session.setAttribute(LoginConstants.LOGIN_MESSAGE, exception.getLocalizedMessage());
|
||||
session.setAttribute("loginId", username);
|
||||
String contextPath = request.getContextPath();
|
||||
response.sendRedirect(contextPath + "/login");
|
||||
}
|
||||
|
||||
private void logLoginFailure(HttpServletRequest request, String username, AuthenticationException exception) {
|
||||
StringBuilder logMessage = new StringBuilder();
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("USER LOGIN FAILURE\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("Username: ").append(username).append("\n");
|
||||
logMessage.append("Session ID: ").append(request.getSession().getId()).append("\n");
|
||||
logMessage.append("Failed At: ").append(LocalDateTime.now().format(formatter)).append("\n");
|
||||
logMessage.append("Failure Reason: ").append(exception.getLocalizedMessage()).append("\n");
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("REQUEST INFORMATION\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
|
||||
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
|
||||
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
|
||||
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
|
||||
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
|
||||
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
|
||||
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
|
||||
sessionLogger.warn(logMessage.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.eactive.apim.portal.config;
|
||||
|
||||
import com.eactive.apim.portal.apps.user.repository.PortalOrgRepository;
|
||||
import com.eactive.apim.portal.apps.user.service.PortalUserLogService;
|
||||
import com.eactive.apim.portal.common.util.HttpRequestUtil;
|
||||
import com.eactive.apim.portal.common.util.StringRepeatUtil;
|
||||
import com.eactive.apim.portal.invitation.entity.UserInvitation;
|
||||
import com.eactive.apim.portal.invitation.entity.UserInvitationEnums.InvitationStatus;
|
||||
import com.eactive.apim.portal.invitation.repository.UserInvitationRepository;
|
||||
@@ -15,6 +17,8 @@ import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -26,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -34,6 +39,9 @@ import java.util.Optional;
|
||||
@RequiredArgsConstructor
|
||||
public class PortalAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
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 final PortalUserRepository portalUserRepository;
|
||||
private final PortalProperties portalProperties;
|
||||
private final PortalUserLogService userLogService;
|
||||
@@ -104,6 +112,9 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||
}
|
||||
}
|
||||
|
||||
// 로그인 성공 시 세션 정보 로깅
|
||||
logLoginSuccess(request, session, username);
|
||||
|
||||
String decisionToken = (String) request.getSession().getAttribute("decisionToken");
|
||||
if (decisionToken != null) {
|
||||
response.sendRedirect(contextPath + "/signup/decision_process");
|
||||
@@ -112,6 +123,31 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||
}
|
||||
}
|
||||
|
||||
private void logLoginSuccess(HttpServletRequest request, HttpSession session, String username) {
|
||||
StringBuilder logMessage = new StringBuilder();
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("USER LOGIN SUCCESS\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("Username: ").append(username).append("\n");
|
||||
logMessage.append("Session ID: ").append(session.getId()).append("\n");
|
||||
logMessage.append("Login At: ").append(LocalDateTime.now().format(formatter)).append("\n");
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("REQUEST INFORMATION\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
|
||||
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
|
||||
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
|
||||
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
|
||||
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
|
||||
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
|
||||
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
|
||||
sessionLogger.info(logMessage.toString());
|
||||
}
|
||||
|
||||
private boolean isPasswordChangeRequired(PortalUser user) {
|
||||
// 가장 최근 비밀번호 변경 이력 조회
|
||||
Optional<UserPasswordHistory> latestHistory = passwordHistoryRepository
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.eactive.apim.portal.config;
|
||||
|
||||
import com.eactive.apim.portal.common.util.HttpRequestUtil;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
@@ -29,7 +30,7 @@ public class PortalConfigLog {
|
||||
String method = request.getMethod();
|
||||
String path = request.getRequestURI();
|
||||
String query = request.getQueryString();
|
||||
String ip = request.getRemoteAddr();
|
||||
String ip = HttpRequestUtil.getClientIpAddress(request);
|
||||
|
||||
String user = SecurityUtil.getCurrentLoginId();
|
||||
|
||||
|
||||
@@ -31,13 +31,17 @@ public class PortalConfigSecurity {
|
||||
|
||||
private final PortalAuthenticationManager portalAuthenticationManager;
|
||||
|
||||
private final PortalLogoutSuccessHandler logoutSuccessHandler;
|
||||
|
||||
@Autowired
|
||||
public PortalConfigSecurity(PortalAuthenticationFailureHandler authenticationFailureHandler,
|
||||
PortalAuthenticationSuccessHandler authenticationSuccessHandler,
|
||||
PortalAuthenticationManager portalAuthenticationManager) {
|
||||
PortalAuthenticationManager portalAuthenticationManager,
|
||||
PortalLogoutSuccessHandler logoutSuccessHandler) {
|
||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||
this.authenticationSuccessHandler = authenticationSuccessHandler;
|
||||
this.portalAuthenticationManager = portalAuthenticationManager;
|
||||
this.logoutSuccessHandler = logoutSuccessHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -71,7 +75,7 @@ public class PortalConfigSecurity {
|
||||
.successHandler(authenticationSuccessHandler))
|
||||
.logout(logout -> logout
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET"))
|
||||
.logoutSuccessUrl("/"))
|
||||
.logoutSuccessHandler(logoutSuccessHandler))
|
||||
.csrf(csrf -> csrf
|
||||
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
|
||||
.ignoringRequestMatchers(new AntPathRequestMatcher("/_proxy/**/*"))
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.eactive.apim.portal.config;
|
||||
|
||||
import com.eactive.apim.portal.common.util.HttpRequestUtil;
|
||||
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.LogoutSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* 로그아웃 성공 시 세션 정보를 로깅하는 핸들러
|
||||
*/
|
||||
@Component
|
||||
public class PortalLogoutSuccessHandler implements 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");
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException, ServletException {
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
if (session != null) {
|
||||
StringBuilder logMessage = new StringBuilder();
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("USER LOGOUT\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("Session ID: ").append(session.getId()).append("\n");
|
||||
logMessage.append("Logout At: ").append(LocalDateTime.now().format(formatter)).append("\n");
|
||||
|
||||
if (authentication != null) {
|
||||
logMessage.append("Username: ").append(authentication.getName()).append("\n");
|
||||
logMessage.append("Authenticated: ").append(authentication.isAuthenticated()).append("\n");
|
||||
}
|
||||
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("REQUEST INFORMATION\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
|
||||
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
|
||||
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
|
||||
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
|
||||
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
|
||||
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
|
||||
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
|
||||
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("SESSION ATTRIBUTES (Before Invalidation)\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
|
||||
try {
|
||||
Enumeration<String> attributeNames = session.getAttributeNames();
|
||||
while (attributeNames.hasMoreElements()) {
|
||||
String attrName = attributeNames.nextElement();
|
||||
Object attrValue = session.getAttribute(attrName);
|
||||
String valueStr = attrValue != null ? attrValue.toString() : "null";
|
||||
if (valueStr.length() > 100) {
|
||||
valueStr = valueStr.substring(0, 97) + "...";
|
||||
}
|
||||
logMessage.append(String.format(" %-30s : %s\n", attrName, valueStr));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logMessage.append(" Unable to retrieve session attributes\n");
|
||||
}
|
||||
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
|
||||
sessionLogger.info(logMessage.toString());
|
||||
}
|
||||
|
||||
response.sendRedirect(request.getContextPath() + "/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.eactive.apim.portal.config;
|
||||
|
||||
import com.eactive.apim.portal.common.util.HttpRequestUtil;
|
||||
import com.eactive.apim.portal.common.util.StringRepeatUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* HttpSession 생성 시 요청 헤더 정보를 로깅하는 리스너
|
||||
*/
|
||||
@Component
|
||||
public class SessionLoggingListener implements HttpSessionListener {
|
||||
|
||||
private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
|
||||
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent se) {
|
||||
HttpSession session = se.getSession();
|
||||
|
||||
// HttpServletRequest 가져오기
|
||||
HttpServletRequest request = (HttpServletRequest) session.getAttribute("org.springframework.web.context.request.RequestContextListener.REQUEST_ATTRIBUTES");
|
||||
|
||||
// Spring의 RequestContextHolder를 통해 현재 요청 가져오기
|
||||
try {
|
||||
org.springframework.web.context.request.RequestAttributes requestAttributes =
|
||||
org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();
|
||||
|
||||
if (requestAttributes instanceof org.springframework.web.context.request.ServletRequestAttributes) {
|
||||
request = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// RequestContextHolder를 통해 요청을 가져올 수 없는 경우 무시
|
||||
}
|
||||
|
||||
StringBuilder logMessage = new StringBuilder();
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("NEW HTTP SESSION CREATED\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("Session ID: ").append(session.getId()).append("\n");
|
||||
logMessage.append("Created At: ").append(LocalDateTime.now().format(formatter)).append("\n");
|
||||
logMessage.append("Max Inactive Interval: ").append(session.getMaxInactiveInterval()).append(" seconds\n");
|
||||
|
||||
if (request != null) {
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("REQUEST INFORMATION\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
|
||||
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
|
||||
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
|
||||
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
|
||||
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
|
||||
logMessage.append("Remote Port: ").append(request.getRemotePort()).append("\n");
|
||||
logMessage.append("Request Method: ").append(request.getMethod()).append("\n");
|
||||
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
|
||||
logMessage.append("Request URL: ").append(request.getRequestURL()).append("\n");
|
||||
logMessage.append("Query String: ").append(request.getQueryString()).append("\n");
|
||||
logMessage.append("Protocol: ").append(request.getProtocol()).append("\n");
|
||||
logMessage.append("Scheme: ").append(request.getScheme()).append("\n");
|
||||
logMessage.append("Server Name: ").append(request.getServerName()).append("\n");
|
||||
logMessage.append("Server Port: ").append(request.getServerPort()).append("\n");
|
||||
logMessage.append("Context Path: ").append(request.getContextPath()).append("\n");
|
||||
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("REQUEST HEADERS\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
Enumeration<String> headerValues = request.getHeaders(headerName);
|
||||
while (headerValues.hasMoreElements()) {
|
||||
String headerValue = headerValues.nextElement();
|
||||
logMessage.append(String.format(" %-30s : %s\n", headerName, headerValue));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logMessage.append("\n");
|
||||
logMessage.append("WARNING: HttpServletRequest not available\n");
|
||||
}
|
||||
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
|
||||
sessionLogger.info(logMessage.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent se) {
|
||||
HttpSession session = se.getSession();
|
||||
|
||||
StringBuilder logMessage = new StringBuilder();
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("HTTP SESSION DESTROYED\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
logMessage.append("Session ID: ").append(session.getId()).append("\n");
|
||||
logMessage.append("Destroyed At: ").append(LocalDateTime.now().format(formatter)).append("\n");
|
||||
logMessage.append("Max Inactive Interval: ").append(session.getMaxInactiveInterval()).append(" seconds\n");
|
||||
|
||||
// 세션 속성 정보 로깅
|
||||
try {
|
||||
logMessage.append("\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
logMessage.append("SESSION ATTRIBUTES\n");
|
||||
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
|
||||
|
||||
java.util.Enumeration<String> attributeNames = session.getAttributeNames();
|
||||
while (attributeNames.hasMoreElements()) {
|
||||
String attrName = attributeNames.nextElement();
|
||||
Object attrValue = session.getAttribute(attrName);
|
||||
logMessage.append(String.format(" %-30s : %s\n", attrName, attrValue));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logMessage.append(" Unable to retrieve session attributes\n");
|
||||
}
|
||||
|
||||
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
|
||||
|
||||
sessionLogger.info(logMessage.toString());
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,17 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/http-session.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="FILE"/>
|
||||
@@ -79,4 +90,8 @@
|
||||
<logger name="com.atomikos" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="FILE_HIBERNATE" />
|
||||
</logger>
|
||||
|
||||
<logger name="eapim.portal.session" level="INFO" additivity="false">
|
||||
<appender-ref ref="HTTP_SESSION" />
|
||||
</logger>
|
||||
</configuration>
|
||||
@@ -30,6 +30,17 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/http-session.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -65,4 +76,8 @@
|
||||
<logger name="com.atomikos" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="FILE_HIBERNATE" />
|
||||
</logger>
|
||||
|
||||
<logger name="eapim.portal.session" level="INFO" additivity="false">
|
||||
<appender-ref ref="HTTP_SESSION" />
|
||||
</logger>
|
||||
</configuration>
|
||||
@@ -38,6 +38,17 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/http-session.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="FILE"/>
|
||||
@@ -79,4 +90,8 @@
|
||||
<appender-ref ref="FILE_REPORT" />
|
||||
</logger>
|
||||
|
||||
<logger name="eapim.portal.session" level="INFO" additivity="false">
|
||||
<appender-ref ref="HTTP_SESSION" />
|
||||
</logger>
|
||||
|
||||
</configuration>
|
||||
@@ -46,6 +46,17 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/http-session.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder><Pattern>${CONSOLE_PATTERN}</Pattern></encoder>
|
||||
</appender>
|
||||
@@ -55,6 +66,10 @@
|
||||
<appender-ref ref="NEED_FIX" />
|
||||
</logger>
|
||||
|
||||
<logger name="eapim.portal.session" level="INFO" additivity="false">
|
||||
<appender-ref ref="HTTP_SESSION" />
|
||||
</logger>
|
||||
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="ROLLING"/>
|
||||
|
||||
Reference in New Issue
Block a user