티스토리 뷰
🔧 환경
- java 1.8
- spring
- jsp
- javascript
- sweetalert
🔎 요구사항
- 사용자의 마지막 동작으로 부터 1시간이 지나면 세션을 만료하되, 만료되기 1분전에 세션 만료 알림을 띄어 연장할 수 있어야 한다.
🔎 idea
- server에 filter를 등록하여 요청이 올 때마다 response에 마지막 요청시간을 cookie를 저장하고,
front단에서는 cookie를 1초마다 확인하여 세션 만료 1시간 전 알림을 보내준다.
- 세션 만료 시간 = 마지막 요청 시간 + 1시간
📌 구현
💻 server
1. web.xml 설정
- web.xml에 기본 세션 만료 시간을 설정한다.
- web.xml에 설정한 timeout의 단위는 '분' 이다.
<session-config>
<session-timeout>60</session-timeout>
</session-config>
2. filter 생성 및 등록
1) filter 생성
- 서버시간+타임아웃을 더한 시간을 sessionExpiry라는 쿠키에 담는다.
package com.egovframework.common.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
public class SessionTimeoutCookieFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//쿠키에 저장하는 시간의 단위는 millisecond
//session만료시간 = 서버시간 + web.xml에 설정한 시간 *1000 (단위를 맞추기 위해 *1000)
long sessionExpiryTime = System.currentTimeMillis() + request.getSession().getMaxInactiveInterval() * 1000;
//새로운 쿠키를 생성한다. 쿠키명 : sessionExpiry
Cookie sessionExpiryCookie = new Cookie("sessionExpiry", Long.toString(sessionExpiryTime));
sessionExpiryCookie.setPath("/BotMain_VM");
//response에 쿠키를 담아준다.
response.addCookie(sessionExpiryCookie);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
2) filter 등록
- web.xml에 위에서 만든 필터를 등록해준다.
<filter>
<filter-name>SessionTimeoutCookieFilter</filter-name>
<filter-class>com.egovframework.common.filter.SessionTimeoutCookieFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionTimeoutCookieFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
🎈 front
- 해당 소스는 모든 페이지마다 적용해야하므로, 모든 페이지에 공통으로 들어가는 header.jsp에다 작성했다
- server에서 저장한 쿠키 sessionExpiry와 클라이언트 시간을 비교하여 세션 만료 여부 및 알림 여부를 결정한다.
- sessionAlertCheck와 isSessionExpired는 합칠 수 있을 것 같은데..이름이 명확한게 좋을 것 같아서...따로 나뒀다🙄
함수명 | 설명 |
sessionAlertCheck(offset) | 세션 만료 offset만큼의 시간전에 사용자에게 알림을 줘야하는지를 판단한다. |
isSessionExpired | 세션이 만료되었는지를 판단한다. |
alertSessionExpiredAndLogout | 세션이 만료되었다는 알림 후 메인 페이지로 이동한다. |
checkSessionExpired | setInterval에 등록하여 세션 만료 여부와 알림여부를 확인 후 알림을 준다. |
/**
* @name sessionAlertCheck
* @param offset(millisecond)
* @description 세션 만료 되기 전에 알림 여부 확인
* offset 만큼 세션만료 되기 전에 알림을 줘야하는지 판단한다.
* 예) offset=1000*10 인경우 세션 만료 1시간 전에 알림 여부 true를 반환
* @author injeong.cheon
* @returns {boolean}
*/
const sessionAlertCheck = (offset) => {
const sessionExpiry = Math.abs(getCookie('sessionExpiry')) - (offset);
const time = new Date().getTime();
if ( time - sessionExpiry > 0 ) {
return true;
}
return false;
}
/**
* @name isSessionExpired
* @description 세션 만료 여부 확인
* @author injeong.cheon
* @returns {boolean}
*/
const isSessionExpired = () => {
const sessionExpiry = Math.abs(getCookie('sessionExpiry'));
const time = new Date().getTime();
if ( time - sessionExpiry > 0) {
return true;
}
return false;
}
/**
* @name alertSessionExpiredAndLogout
* @author injeong.cheon
* @description 세션 종료 알림 후 로그아웃 or 팝업창 닫기
*/
const alertSessionExpiredAndLogout = () => {
let text = '세션이 종료 되어 로그인 페이지로 이동합니다.';
let action = () => {
location.href = '/';
}
if (opener) {
text = '세션이 종료 되어 페이지를 닫습니다.';
action = () => {
window.close();
}
}
swal({
title : "알림",
icon : "warning",
text : text,
closeOnClickOutside : false
}).then(function(){
action();
});
}
/**
* @name checkSessionExpired
* @author injeong.cheon
* @description 세션 만료 전 알림
*/
const checkSessionExpired = () => {
//알림 여부를 판단한다.
const alertFlag = sessionAlertCheck(1000 * 60);
if (alertFlag === true) {
if (isSessionExpired()) {
alertSessionExpiredAndLogout();
} else {
swal('알림', "1분 후 세션이 만료됩니다. 세션을 연장하시겠습니까? ", "warning", {
buttons: ["취소", "연장"],
}).then(function (willExtend) {
//연장을 선택한 경우 쿠키를 새롭게 셋팅해준다. 현재시간 + 한시간
if (willExtend) {
setCookie('sessionExpiry', new Date().getTime() + (1000*10*60));
//연장하지 않는 경우에는
} else {
//interval을 clear하고
clearInterval(checkSessionInterval);
//세션종료 타이머를 생성한다.
//timeout = 세션만료 시간 - 현재시간
const timeout = getCookie('sessionExpiry') - new Date().getTime();
setTimeout(()=> {
alertSessionExpiredAndLogout();
},timeout);
}
});
}
}
}
//세션 만료시간을 지속적으로 확인 할 수 있게 interval설정
const checkSessionInterval = setInterval(checkSessionExpired, 1000);
🧐개선점 / 생각 해봐야할 점
- 연장 취소를 누른 경우 타이머를 삭제했기 때문에 해당 페이지에서 타이머 만료 전에 서버에 새로운 요청을 보내도 세션은 연장되지 않는다.
- 연장 취소를 누른 경우 세션 만료 전 다른 페이지로 이동하면 타이머가 다시 실행된다.
'백엔드 > spring' 카테고리의 다른 글
- Total
- Today
- Yesterday
- 코테
- react
- Linux
- Docker
- 자바
- 자바스크립트
- Kubernetes
- 전자정부프레임워크
- java 코테
- 리액트
- softeer java
- 현대
- 스프링
- java
- 현대오토에버
- javascript
- tomcat
- springboot
- 쿠버네티스
- mysql
- 코딩테스트
- 오토에버코테
- Spring
- 현대코테
- centos
- 도커
- 자바코테
- 아파치카프카
- softeer
- 톰캣
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |