From a8cd590a117ea6ae2cd44e59d0d6b830f51d4fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Sun, 8 Mar 2026 19:01:03 +0800 Subject: [PATCH] Require access token presence in MainContainer auth gate before route entry Co-Authored-By: Codex --- src/views/MainContainer.vue | 38 ++++++++++++++------------ tests/views/MainContainerGuard.test.js | 13 ++++++++- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/views/MainContainer.vue b/src/views/MainContainer.vue index cd096e4..f5e2cf0 100644 --- a/src/views/MainContainer.vue +++ b/src/views/MainContainer.vue @@ -56,23 +56,22 @@ export default { async beforeRouteEnter(to, from, next) { const loginStore = useLoginStoreInGuard(); const relativeReturnTo = `${window.location.pathname}${window.location.search}${window.location.hash}`; + const hasLoginMarker = Boolean(getCookie("isLuciaLoggedIn")); + const hasAccessToken = Boolean(getCookie("luciaToken")); + const hasRefreshToken = Boolean(getCookie("luciaRefreshToken")); - if (!getCookie("isLuciaLoggedIn")) { - if (getCookie("luciaRefreshToken")) { - try { - await loginStore.refreshToken(); - loginStore.setIsLoggedIn(true); - setCookie("isLuciaLoggedIn", "true"); - next(); - } catch (error) { - next({ - path: "/login", - query: { - "return-to": btoa(relativeReturnTo), - }, - }); - } - } else { + if (hasLoginMarker && hasAccessToken) { + next(); + return; + } + + if (hasRefreshToken) { + try { + await loginStore.refreshToken(); + loginStore.setIsLoggedIn(true); + setCookie("isLuciaLoggedIn", "true"); + next(); + } catch (error) { next({ path: "/login", query: { @@ -81,7 +80,12 @@ export default { }); } } else { - next(); + next({ + path: "/login", + query: { + "return-to": btoa(relativeReturnTo), + }, + }); } }, // Remember, Swal modal handling is called before beforeRouteUpdate diff --git a/tests/views/MainContainerGuard.test.js b/tests/views/MainContainerGuard.test.js index 68e0c1f..feda71e 100644 --- a/tests/views/MainContainerGuard.test.js +++ b/tests/views/MainContainerGuard.test.js @@ -84,14 +84,25 @@ describe("MainContainer beforeRouteEnter", () => { ); }); - it("calls next() when already logged in", async () => { + it("calls next() when logged-in marker and access token both exist", async () => { document.cookie = "isLuciaLoggedIn=true"; + document.cookie = "luciaToken=token"; await callGuard(); expect(next).toHaveBeenCalled(); }); + it("redirects to login when logged-in marker exists without access token", async () => { + document.cookie = "isLuciaLoggedIn=true"; + + await callGuard(); + + expect(next).toHaveBeenCalledWith( + expect.objectContaining({ path: "/login" }), + ); + }); + it("stores a relative return-to path when redirecting to login", async () => { window.history.replaceState( {},