diff --git a/gateway/html/login.html b/gateway/html/login.html
index 15440d2..7874a03 100644
--- a/gateway/html/login.html
+++ b/gateway/html/login.html
@@ -201,8 +201,20 @@
}
}
+ // logout=1 파라미터가 있으면 모든 인증 데이터 정리
+ var isLogout = new URLSearchParams(location.search).get('logout') === '1';
+ if (isLogout) {
+ ssoCookie.remove('sso_token');
+ ssoCookie.remove('sso_user');
+ ssoCookie.remove('sso_refresh_token');
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(function(k) {
+ localStorage.removeItem(k);
+ });
+ }
+
// 이미 로그인 되어있으면 포털로 (쿠키 또는 localStorage 체크 + 만료 확인)
- var existingToken = ssoCookie.get('sso_token') || localStorage.getItem('sso_token');
+ var existingToken = isLogout ? null : (ssoCookie.get('sso_token') || localStorage.getItem('sso_token'));
if (existingToken && existingToken !== 'undefined' && existingToken !== 'null') {
if (isTokenValid(existingToken)) {
// 쿠키 재설정 (localStorage에만 있고 쿠키가 없는 경우 대비)
diff --git a/gateway/html/shared/nav-header.js b/gateway/html/shared/nav-header.js
index fb27418..f888494 100644
--- a/gateway/html/shared/nav-header.js
+++ b/gateway/html/shared/nav-header.js
@@ -51,7 +51,7 @@
['sso_token','sso_user','sso_refresh_token','token','user','access_token','currentUser','current_user','userInfo','userPageAccess'].forEach(function(k) {
localStorage.removeItem(k);
});
- window.location.href = this.getLoginUrl();
+ window.location.href = this.getLoginUrl(window.location.href) + '&logout=1';
},
/**
diff --git a/system1-factory/web/js/api-base.js b/system1-factory/web/js/api-base.js
index 322ec5a..432054e 100644
--- a/system1-factory/web/js/api-base.js
+++ b/system1-factory/web/js/api-base.js
@@ -154,7 +154,7 @@ if ('caches' in window) {
// 401 Unauthorized 처리
if (response.status === 401) {
window.clearSSOAuth();
- window.location.href = window.getLoginUrl();
+ window.location.href = window.getLoginUrl() + '&logout=1';
throw new Error('인증이 만료되었습니다.');
}
diff --git a/system1-factory/web/js/auth-check.js b/system1-factory/web/js/auth-check.js
index 939c9d0..76b145b 100644
--- a/system1-factory/web/js/auth-check.js
+++ b/system1-factory/web/js/auth-check.js
@@ -120,8 +120,24 @@ async function checkPageAccess(pageKey) {
}
}
+// 쿠키 직접 읽기 (api-base.js의 cookieGet은 IIFE 내부 함수이므로 접근 불가)
+function _authCookieGet(name) {
+ var match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
+ return match ? decodeURIComponent(match[1]) : null;
+}
+
// 즉시 실행 함수로 스코프를 보호하고 로직을 실행
(async function() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ var cookieToken = _authCookieGet('sso_token');
+ var localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(function(k) { localStorage.removeItem(k); });
+ window.location.href = window.getLoginUrl ? window.getLoginUrl() : '/login';
+ return;
+ }
+
if (!isLoggedIn()) {
clearAuthData(); // 만약을 위해 한번 더 정리
window.location.href = window.getLoginUrl ? window.getLoginUrl() : '/login';
diff --git a/system2-report/web/js/app-init.js b/system2-report/web/js/app-init.js
index 97fc474..765cc53 100644
--- a/system2-report/web/js/app-init.js
+++ b/system2-report/web/js/app-init.js
@@ -19,6 +19,12 @@
window.location.href = window.getLoginUrl ? window.getLoginUrl() : '/login';
}
+ // ===== 쿠키 직접 읽기 (api-base.js의 cookieGet은 IIFE 내부이므로) =====
+ function cookieGet(name) {
+ var match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
+ return match ? decodeURIComponent(match[1]) : null;
+ }
+
// ===== 인증 함수 (api-base.js의 전역 헬퍼 활용) =====
function isLoggedIn() {
var token = window.getSSOToken ? window.getSSOToken() : localStorage.getItem('sso_token');
@@ -40,6 +46,16 @@
// ===== 메인 초기화 =====
async function init() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ var cookieToken = cookieGet('sso_token');
+ var localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(function(k) { localStorage.removeItem(k); });
+ safeRedirectToLogin();
+ return;
+ }
+
// 1. 인증 확인
if (!isLoggedIn()) {
clearAuthData();
diff --git a/system3-nonconformance/web/static/js/app.js b/system3-nonconformance/web/static/js/app.js
index a6b8290..bc301d6 100644
--- a/system3-nonconformance/web/static/js/app.js
+++ b/system3-nonconformance/web/static/js/app.js
@@ -46,8 +46,17 @@ class App {
* 인증 확인
*/
async checkAuth() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ const cookieToken = this._cookieGet('sso_token');
+ const localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
+ throw new Error('쿠키 없음 - 로그아웃 상태');
+ }
+
// SSO 쿠키 우선, localStorage 폴백
- const token = this._cookieGet('sso_token') || localStorage.getItem('sso_token');
+ const token = cookieToken || localToken;
if (!token) {
throw new Error('토큰 없음');
}
diff --git a/system3-nonconformance/web/static/js/core/auth-manager.js b/system3-nonconformance/web/static/js/core/auth-manager.js
index 3d9fd3c..4762bc1 100644
--- a/system3-nonconformance/web/static/js/core/auth-manager.js
+++ b/system3-nonconformance/web/static/js/core/auth-manager.js
@@ -97,6 +97,15 @@ class AuthManager {
* 저장소에서 사용자 정보 복원 (SSO 쿠키 + localStorage)
*/
restoreUserFromStorage() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ const cookieToken = this._cookieGet('sso_token');
+ const localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
+ return;
+ }
+
const token = this._getToken();
const user = this._getUser();
@@ -240,7 +249,7 @@ class AuthManager {
logout() {
this.clearAuth();
this.notifyListeners('logout');
- window.location.href = this._getLoginUrl();
+ window.location.href = this._getLoginUrl() + '&logout=1';
}
/**
diff --git a/tkpurchase/web/static/js/tkpurchase-core.js b/tkpurchase/web/static/js/tkpurchase-core.js
index 4903eb1..29e3857 100644
--- a/tkpurchase/web/static/js/tkpurchase-core.js
+++ b/tkpurchase/web/static/js/tkpurchase-core.js
@@ -79,7 +79,7 @@ function doLogout() {
if (!confirm('로그아웃?')) return;
_cookieRemove('sso_token'); _cookieRemove('sso_user'); _cookieRemove('sso_refresh_token');
['sso_token','sso_user','sso_refresh_token','token','user','access_token','currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
- location.href = getLoginUrl();
+ location.href = getLoginUrl() + '&logout=1';
}
/* ===== Navbar ===== */
@@ -106,6 +106,16 @@ let currentUser = null;
/* ===== Init ===== */
function initAuth() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ const cookieToken = _cookieGet('sso_token');
+ const localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
+ _safeRedirect();
+ return false;
+ }
+
const token = getToken();
if (!token) { _safeRedirect(); return false; }
const decoded = decodeToken(token);
diff --git a/tksafety/web/static/js/tksafety-core.js b/tksafety/web/static/js/tksafety-core.js
index 17e0faf..38ead95 100644
--- a/tksafety/web/static/js/tksafety-core.js
+++ b/tksafety/web/static/js/tksafety-core.js
@@ -76,7 +76,7 @@ function doLogout() {
if (!confirm('로그아웃?')) return;
_cookieRemove('sso_token'); _cookieRemove('sso_user'); _cookieRemove('sso_refresh_token');
['sso_token','sso_user','sso_refresh_token','token','user','access_token','currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
- location.href = getLoginUrl();
+ location.href = getLoginUrl() + '&logout=1';
}
/* ===== Navbar ===== */
@@ -100,6 +100,16 @@ let currentUser = null;
/* ===== Init ===== */
function initAuth() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ const cookieToken = _cookieGet('sso_token');
+ const localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
+ _safeRedirect();
+ return false;
+ }
+
const token = getToken();
if (!token) { _safeRedirect(); return false; }
const decoded = decodeToken(token);
diff --git a/user-management/web/static/js/tkuser-core.js b/user-management/web/static/js/tkuser-core.js
index 0848e81..8de4b23 100644
--- a/user-management/web/static/js/tkuser-core.js
+++ b/user-management/web/static/js/tkuser-core.js
@@ -75,7 +75,7 @@ function doLogout() {
if (!confirm('로그아웃?')) return;
_cookieRemove('sso_token'); _cookieRemove('sso_user'); _cookieRemove('sso_refresh_token');
['sso_token','sso_user','sso_refresh_token','token','user','access_token','currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
- location.href = getLoginUrl();
+ location.href = getLoginUrl() + '&logout=1';
}
/* ===== State ===== */
@@ -83,6 +83,16 @@ let currentUser = null;
/* ===== Init ===== */
async function init() {
+ // 쿠키 우선 검증: 쿠키 없고 localStorage에만 토큰이 있으면 정리
+ const cookieToken = _cookieGet('sso_token');
+ const localToken = localStorage.getItem('sso_token');
+ if (!cookieToken && localToken) {
+ ['sso_token','sso_user','sso_refresh_token','token','user','access_token',
+ 'currentUser','current_user','userInfo','userPageAccess'].forEach(k => localStorage.removeItem(k));
+ _safeRedirect();
+ return;
+ }
+
const token = getToken();
if (!token) { _safeRedirect(); return; }
const decoded = decodeToken(token);