From 7b50b599cf2de33019f542f33a9c3a3b0db45113 Mon Sep 17 00:00:00 2001 From: canglan Date: Fri, 21 Aug 2026 20:52:41 +0800 Subject: [PATCH] fix: infinite login loop from async auth validation - Add _validating flag to prevent recursive hashchange calls during async token validation - route() checks _validating before calling validateAuth(), sets flag before async call, clears in .then/.catch handlers - route() returns early if still validating (waits for completion) - Fixes: expired token causing infinite login redirect loop --- public/js/app.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index e7826e4..e6931cd 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -95,13 +95,19 @@ const App = { closeModal() { document.getElementById('modal-overlay').classList.add('hidden'); }, navigate(page, param) { location.hash = `#/${page}` + (param ? `/${param}` : ''); }, + _validating: false, + // 验证 token 有效性(轻量级,失败则清除登录态) async validateAuth() { - if (!Auth.logged()) return false; + if (this._validating) return null; // 防止递归 + this._validating = true; + if (!Auth.logged()) { this._validating = false; return false; } try { await API.get('/me'); + this._validating = false; return true; } catch (e) { + this._validating = false; if (e && e.message && e.message.includes('登录')) { Auth.reset(); return false; @@ -126,17 +132,27 @@ const App = { if (page === 'login' || page === 'register' || page === 'forgot' || page === 'reset') { this.showPublic(page); return; } // 访问受保护页面前先验证 token 有效性 - if (Auth.logged()) { + if (Auth.logged() && !this._validating) { + this._validating = true; // 标记正在验证 this.validateAuth().then(valid => { - if (!valid) { location.hash = '#/login'; return; } + this._validating = false; + if (!valid) { + location.hash = '#/login'; + return; + } this._doRoute(page, param); }).catch(() => { + this._validating = false; Auth.reset(); location.hash = '#/login'; }); return; } - location.hash = '#/login'; + if (!Auth.logged()) { + location.hash = '#/login'; + return; + } + // 正在验证中,不做任何操作(等待验证完成) }, _doRoute(page, param) {