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
This commit is contained in:
2026-08-21 20:52:41 +08:00
parent e232f3b02e
commit 7b50b599cf

View File

@@ -95,13 +95,19 @@ const App = {
closeModal() { document.getElementById('modal-overlay').classList.add('hidden'); }, closeModal() { document.getElementById('modal-overlay').classList.add('hidden'); },
navigate(page, param) { location.hash = `#/${page}` + (param ? `/${param}` : ''); }, navigate(page, param) { location.hash = `#/${page}` + (param ? `/${param}` : ''); },
_validating: false,
// 验证 token 有效性(轻量级,失败则清除登录态) // 验证 token 有效性(轻量级,失败则清除登录态)
async validateAuth() { async validateAuth() {
if (!Auth.logged()) return false; if (this._validating) return null; // 防止递归
this._validating = true;
if (!Auth.logged()) { this._validating = false; return false; }
try { try {
await API.get('/me'); await API.get('/me');
this._validating = false;
return true; return true;
} catch (e) { } catch (e) {
this._validating = false;
if (e && e.message && e.message.includes('登录')) { if (e && e.message && e.message.includes('登录')) {
Auth.reset(); Auth.reset();
return false; return false;
@@ -126,17 +132,27 @@ const App = {
if (page === 'login' || page === 'register' || page === 'forgot' || page === 'reset') { this.showPublic(page); return; } if (page === 'login' || page === 'register' || page === 'forgot' || page === 'reset') { this.showPublic(page); return; }
// 访问受保护页面前先验证 token 有效性 // 访问受保护页面前先验证 token 有效性
if (Auth.logged()) { if (Auth.logged() && !this._validating) {
this._validating = true; // 标记正在验证
this.validateAuth().then(valid => { this.validateAuth().then(valid => {
if (!valid) { location.hash = '#/login'; return; } this._validating = false;
if (!valid) {
location.hash = '#/login';
return;
}
this._doRoute(page, param); this._doRoute(page, param);
}).catch(() => { }).catch(() => {
this._validating = false;
Auth.reset(); Auth.reset();
location.hash = '#/login'; location.hash = '#/login';
}); });
return; return;
} }
if (!Auth.logged()) {
location.hash = '#/login'; location.hash = '#/login';
return;
}
// 正在验证中,不做任何操作(等待验证完成)
}, },
_doRoute(page, param) { _doRoute(page, param) {