application.properties에서 타임아웃 설정
embedded tomcat을 사용한다면 기본적으로 application.properties에 다음 property로 세션 타임아웃 설정이 가능하다.
application.properties:109
# session timeout: unit default SECOND - default 120 minutes
server.servlet.session.timeout=10
위에서 설정된 Property값은 부팅시 아래 configuration에 의해 시스템에 로딩된다.
org/springframework/boot/spring-boot-autoconfigure/2.5.6/spring-boot-autoconfigure-2.5.6-sources.jar!/org/springframework/boot/autoconfigure/web/ServerProperties.java:45
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
/**
* Server HTTP port.
*/
private Integer port;
/**
* Network address to which the server should bind.
*/
private InetAddress address;
@NestedConfigurationProperty
private final ErrorProperties error = new ErrorProperties();
/**
* Strategy for handling X-Forwarded-* headers.
*/
private ForwardHeadersStrategy forwardHeadersStrategy;
/**
* Value to use for the Server response header (if empty, no header is sent).
*/
private String serverHeader;
/**
* Maximum size of the HTTP message header.
*/
private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8);
/**
* Type of shutdown that the server will support.
*/
private Shutdown shutdown = Shutdown.IMMEDIATE;
@NestedConfigurationProperty
private Ssl ssl;
@NestedConfigurationProperty
private final Compression compression = new Compression();
@NestedConfigurationProperty
private final Http2 http2 = new Http2();
private final Servlet servlet = new Servlet();
private final Tomcat tomcat = new Tomcat();
private final Jetty jetty = new Jetty();
private final Netty netty = new Netty();
private final Undertow undertow = new Undertow();
org/springframework/boot/spring-boot/2.5.6/spring-boot-2.5.6-sources.jar!/org/springframework/boot/web/servlet/server/Session.java:57
/**
* Session properties.
*
* @author Andy Wilkinson
* @since 2.0.0
*/
public class Session {
@DurationUnit(ChronoUnit.SECONDS)
private Duration timeout = Duration.ofMinutes(30);
private Set<Session.SessionTrackingMode> trackingModes;
private boolean persistent;
/**
* Directory used to store session data.
*/
private File storeDir;
private final Cookie cookie = new Cookie();
private final SessionStoreDirectory sessionStoreDirectory = new SessionStoreDirectory();
public Cookie getCookie() {
return this.cookie;
}
public Duration getTimeout() {
return this.timeout;
}
public void setTimeout(Duration timeout) {
this.timeout = timeout;
}
설정된 timeout 값을 가져가는 부분 즉 setTimeout 호출 부를 확인해 보면 다음과 같다.
org/springframework/boot/spring-boot/2.5.6/spring-boot-2.5.6-sources.jar!/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java:420
getSessionTimeoutInMinutes:426, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
configureSession:394, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
configureContext:383, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
prepareContext:246, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
getWebServer:198, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
createWebServer:182, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
onRefresh:160, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:577, AbstractApplicationContext (org.springframework.context.support)
refresh:145, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:754, SpringApplication (org.springframework.boot)
refreshContext:434, SpringApplication (org.springframework.boot)
run:338, SpringApplication (org.springframework.boot)
run:1343, SpringApplication (org.springframework.boot)
run:1332, SpringApplication (org.springframework.boot)
main:27, SdpApplication (com.sdp)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
run:49, RestartLauncher (org.springframework.boot.devtools.restart)
private long getSessionTimeoutInMinutes() {
Duration sessionTimeout = getSession().getTimeout();
if (isZeroOrLess(sessionTimeout)) {
return 0;
}
return Math.max(sessionTimeout.toMinutes(), 1);
}
public long toMinutes() {
return this.seconds / 60L;
}
여기서 주의할 것은... 위 코드를 보면 알겠지만... 설정단위는 분 단위로 관리된다. 즉 sessionTimeout을 1분 미만으로 설정하면 위 메소드에서 1분으로 바꿔버리고 초단위를 /60으로 분으로 환산한다. 나머지는 올림하지 않는다.
Session Listner 로 setMaxInactiveInterval 설정하기
부팅 시 property 값으로 설정하기 외에 동적으로 세션 만료 시간을 바꾸고 싶으면 아래 메소드를 호출하면 된다.
org/apache/tomcat/embed/tomcat-embed-core/9.0.54/tomcat-embed-core-9.0.54-sources.jar!/javax/servlet/http/HttpSession.java:22
public interface HttpSession {
... 생략
/**
* Specifies the time, in seconds, between client requests before the
* servlet container will invalidate this session. A zero or negative time
* indicates that the session should never timeout.
*
* @param interval
* An integer specifying the number of seconds
*/
public void setMaxInactiveInterval(int interval);
페이지 렌더링 시에 세션이 생성되면 아래와 같이 세션 생성이 되고 등록한 세션 리스너를 호출한다.
setMaxInactiveInterval:576, StandardSession (org.apache.catalina.session)
createSession:719, ManagerBase (org.apache.catalina.session)
doGetSession:3093, Request (org.apache.catalina.connector)
getSession:2493, Request (org.apache.catalina.connector)
getSession:908, RequestFacade (org.apache.catalina.connector)
getSession:920, RequestFacade (org.apache.catalina.connector)
getSession:253, HttpServletRequestWrapper (javax.servlet.http)
getSession:253, HttpServletRequestWrapper (javax.servlet.http)
getSession:253, HttpServletRequestWrapper (javax.servlet.http)
getSession:253, HttpServletRequestWrapper (javax.servlet.http)
getSession:253, HttpServletRequestWrapper (javax.servlet.http)
preHandle:30, Interceptor (com.sdp.common.interceptor)
applyPreHandle:148, HandlerExecutionChain (org.springframework.web.servlet)
doDispatch:1062, DispatcherServlet (org.springframework.web.servlet)
doService:963, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:655, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:764, HttpServlet (javax.servlet.http)
internalDoFilter:227, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilter:53, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilter:218, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:212, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilter:36, XssEscapeServletFilter (com.navercorp.lucy.security.xss.servletfilter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilter:327, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
invoke:115, FilterSecurityInterceptor (org.springframework.security.web.access.intercept)
doFilter:81, FilterSecurityInterceptor (org.springframework.security.web.access.intercept)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:121, ExceptionTranslationFilter (org.springframework.security.web.access)
doFilter:115, ExceptionTranslationFilter (org.springframework.security.web.access)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:126, SessionManagementFilter (org.springframework.security.web.session)
doFilter:81, SessionManagementFilter (org.springframework.security.web.session)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:105, AnonymousAuthenticationFilter (org.springframework.security.web.authentication)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:149, SecurityContextHolderAwareRequestFilter (org.springframework.security.web.servletapi)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:63, RequestCacheAwareFilter (org.springframework.security.web.savedrequest)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:149, BasicAuthenticationFilter (org.springframework.security.web.authentication.www)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:103, LogoutFilter (org.springframework.security.web.authentication.logout)
doFilter:89, LogoutFilter (org.springframework.security.web.authentication.logout)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doHeadersAfter:90, HeaderWriterFilter (org.springframework.security.web.header)
doFilterInternal:75, HeaderWriterFilter (org.springframework.security.web.header)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:110, SecurityContextPersistenceFilter (org.springframework.security.web.context)
doFilter:80, SecurityContextPersistenceFilter (org.springframework.security.web.context)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:55, WebAsyncManagerIntegrationFilter (org.springframework.security.web.context.request.async)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:336, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:211, FilterChainProxy (org.springframework.security.web)
doFilter:183, FilterChainProxy (org.springframework.security.web)
invokeDelegate:358, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:271, DelegatingFilterProxy (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:93, FormContentFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
invoke:197, StandardWrapperValve (org.apache.catalina.core)
invoke:97, StandardContextValve (org.apache.catalina.core)
invoke:540, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:135, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:78, StandardEngineValve (org.apache.catalina.core)
service:357, CoyoteAdapter (org.apache.catalina.connector)
service:382, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:895, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1722, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)
run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:834, Thread (java.lang)
세션 리스너는 다음과 같이 구현하고 Application entry에 등록한다.
public class SessionListener implements HttpSessionListener {
@Value("${server.servlet.session.timeout}")
private int SESSION_TIMEOUT;
private Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public void sessionCreated(HttpSessionEvent se) {
se.getSession().setMaxInactiveInterval(SESSION_TIMEOUT); //세션만료60분
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
}
}
@SpringBootApplication
public class SdpApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
@Bean
public HttpSessionListener httpSessionListener(){
return new SessionListener();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SdpApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SdpApplication.class, args);
}
}
'Backend Development > Spring boot' 카테고리의 다른 글
[Spring boot] SAML2.0 SSO 간단 정리 (0) | 2022.05.10 |
---|---|
[Spring boot] OAuth2 login(Google, Facebook, Naver, Kakao) (0) | 2022.03.15 |
[Spring boot] Spring Security 분석 - FilterSecurityInterceptor (Session 인증 기반) (0) | 2022.03.14 |
[Spring boot] Spring Security 분석 - WebSecurityConfigurerAdapter (0) | 2022.03.14 |
[Spring boot] Spring Security 분석 - FilterSecurityInterceptor (Token 인증 기반) (0) | 2022.03.14 |