- 세션 타임아웃 10분 고정: 서버/DB 설정 통일 및 관리 단순화
- CSRF 토큰 조회/재발급 API 추가 - 익명 세션 유지 핑 로직 구현 - OAuth2 가이드 scope 고정값 "api"로 수정
This commit is contained in:
@@ -115,6 +115,24 @@
|
||||
form.checkId.checked = ((form.id.value = getCookie('saveid')) !== null);
|
||||
}
|
||||
|
||||
// CSRF 토큰 재발급 안전망: keepalive ping이 끊긴 경우(절전·네트워크 단절 등)
|
||||
// 세션이 만료됐어도 제출 직전 새 토큰을 받아 403(만료) 대신 정상 로그인되게 한다.
|
||||
// 재발급 실패 시에는 기존 토큰으로 그대로 제출한다.
|
||||
function refreshCsrfAndThen(form, next) {
|
||||
$.ajax({
|
||||
url: /*[[@{/api/session/csrf}]]*/ '/api/session/csrf',
|
||||
type: 'GET',
|
||||
success: function (data) {
|
||||
if (data && data.token) {
|
||||
if (form['_csrf']) { form['_csrf'].value = data.token; }
|
||||
var meta = document.querySelector('meta[name="_csrf"]');
|
||||
if (meta) { meta.content = data.token; }
|
||||
}
|
||||
},
|
||||
complete: function () { next(); }
|
||||
});
|
||||
}
|
||||
|
||||
// 로그인 전 중복 접속 확인 → 중복 시 기존 세션 강제 로그아웃 여부 질의
|
||||
function checkDuplicateAndLogin(form) {
|
||||
var loginId = form.id.value;
|
||||
@@ -157,26 +175,8 @@
|
||||
|
||||
$(function () {
|
||||
|
||||
// CSRF 토큰은 세션 기반 → 세션 만료(server.servlet.session.timeout=10m) 전에
|
||||
// 메인 페이지로 이동시켜 stale 토큰 제출(403) 방지. 이동은 서버 요청이라 세션 idle도 리셋됨.
|
||||
// 단, 입력 중에는 이탈 금지 → idle 타이머(활동 시 리셋, 입력값/포커스 있으면 보류).
|
||||
// 만료 시간은 하드코딩하지 않고 서버 세션 타임아웃(초)을 렌더 시점에 읽어 파생 → yml 변경 시 자동 반영.
|
||||
var SESSION_TIMEOUT_SEC = /*[[${#request.session.maxInactiveInterval}]]*/ 600;
|
||||
var LOGIN_IDLE_LIMIT_MS = Math.max(60, SESSION_TIMEOUT_SEC - 120) * 1000; // 세션 만료 2분 전
|
||||
var loginIdleTimer;
|
||||
function scheduleIdleRedirect() {
|
||||
clearTimeout(loginIdleTimer);
|
||||
loginIdleTimer = setTimeout(function () {
|
||||
var idEl = document.getElementById('id');
|
||||
var pwEl = document.getElementById('password');
|
||||
var busy = document.activeElement === idEl || document.activeElement === pwEl
|
||||
|| (idEl && idEl.value) || (pwEl && pwEl.value);
|
||||
if (busy) { scheduleIdleRedirect(); return; } // 입력 중/입력값 있음 → 이탈 보류
|
||||
window.location.href = /*[[@{/}]]*/ '/';
|
||||
}, LOGIN_IDLE_LIMIT_MS);
|
||||
}
|
||||
$('#id, #password, #checkId').on('input keydown focus click', scheduleIdleRedirect);
|
||||
scheduleIdleRedirect();
|
||||
// 세션 만료 대응은 head의 익명 keepalive ping(/api/session/ping)이 담당하고,
|
||||
// 제출 직전 refreshCsrfAndThen()이 CSRF 토큰 재발급 안전망 역할을 한다.
|
||||
|
||||
var successMsg = [[${success}]];
|
||||
console.log("Success message:", successMsg);
|
||||
@@ -225,7 +225,9 @@
|
||||
$('#loginLoading').removeClass('active');
|
||||
customPopups.showAlert('[[#{login.passLengthShort}]]');
|
||||
} else {
|
||||
checkDuplicateAndLogin(form);
|
||||
refreshCsrfAndThen(form, function () {
|
||||
checkDuplicateAndLogin(form);
|
||||
});
|
||||
}
|
||||
}
|
||||
form.classList.add('was-validated');
|
||||
|
||||
Reference in New Issue
Block a user