41 lines
1.6 KiB
JavaScript
41 lines
1.6 KiB
JavaScript
/** 同源多标签页会话同步:监听 jwt/clear 变更,退出时将当前受保护页面替换为登录页。 */
|
|
import { defineNuxtPlugin } from "#app";
|
|
import { useAuth, isValidJwt } from "~/lib/auth.js";
|
|
import { r as safeRedirect } from "~/lib/auth-redirect.js";
|
|
import { isPublicRoute } from "~/utils/access.js";
|
|
|
|
export default defineNuxtPlugin({
|
|
name: "console-session-sync",
|
|
dependsOn: ["console-ui"],
|
|
setup(app) {
|
|
const auth = useAuth();
|
|
const router = app.$router;
|
|
// 只处理 localStorage 会话事件;读取最新值而非 event.newValue,避免积压事件倒退状态。
|
|
function reconcileSession(event) {
|
|
if (
|
|
event.storageArea !== localStorage ||
|
|
(event.key !== null && event.key !== "jwt")
|
|
)
|
|
return;
|
|
// Read the latest value: several storage events may already be queued.
|
|
const persisted = localStorage.getItem("jwt");
|
|
if (persisted === auth.token) return;
|
|
if (isValidJwt(persisted)) auth.loginWithJwt(persisted);
|
|
else auth.clear();
|
|
const route = router.currentRoute.value;
|
|
if (!auth.isLoggedIn && !isPublicRoute(route)) {
|
|
const redirect = safeRedirect(route.fullPath);
|
|
void router.replace({
|
|
path: "/login",
|
|
query: redirect === "/" ? {} : { redirect },
|
|
});
|
|
}
|
|
}
|
|
window.addEventListener("storage", reconcileSession);
|
|
// 应用销毁时解绑,避免热重载或重新挂载后叠加处理同一 storage 事件。
|
|
app.vueApp.onUnmount(() =>
|
|
window.removeEventListener("storage", reconcileSession),
|
|
);
|
|
},
|
|
});
|