- 세션 타임아웃 10분 고정: 서버/DB 설정 통일 및 관리 단순화
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- CSRF 토큰 조회/재발급 API 추가 - 익명 세션 유지 핑 로직 구현
- OAuth2 가이드 scope 고정값 "api"로 수정
This commit is contained in:
Rinjae
2026-07-23 18:05:57 +09:00
parent c865359819
commit f221c20ece
11 changed files with 95 additions and 50 deletions
@@ -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');