feat: auth route guard

This commit is contained in:
Tony Yang
2025-04-16 16:51:40 +08:00
parent d1d879306a
commit 9ad4313e43
2 changed files with 51 additions and 4 deletions
+26 -3
View File
@@ -61,7 +61,8 @@ const routes = [
component: ProfileView, component: ProfileView,
meta: { meta: {
showInNav: false, showInNav: false,
navName: '個人資料' navName: '個人資料',
requiresAuth: true
} }
}, },
{ {
@@ -71,7 +72,8 @@ const routes = [
meta: { meta: {
keepAlive: true, keepAlive: true,
showInNav: true, showInNav: true,
navName: '每日金句' navName: '每日金句',
requiresAuth: true
} }
} }
]; ];
@@ -84,8 +86,29 @@ const router = createRouter({
export function unauthRedirectToLogin() { export function unauthRedirectToLogin() {
const auth = useAuthStore(); const auth = useAuthStore();
auth.clearJwt(); auth.clearJwt();
alert('Your session has expired. Redirecting to login.'); alert('您的登入驗證已過期。將重新導向至登入頁面。');
router.push('/login'); router.push('/login');
} }
router.beforeEach((to, from, next) => {
const auth = useAuthStore();
if (auth.isLoggedIn && (to.path === '/login' || to.path === '/register')) {
next('/profile');
} else if (to.meta.requiresAuth) {
if (!auth.isLoggedIn) {
auth.clearJwt();
if (auth.isExpired) {
alert('您的登入驗證已過期。將重新導向至登入頁面...');
} else {
alert('請登入以使用此服務。將重新導向至登入頁面...');
}
next('/login');
} else {
next();
}
} else {
next();
}
});
export default router; export default router;
+25 -1
View File
@@ -1,11 +1,35 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
function isJwtExpired(jwt) {
if (!jwt) return true;
try {
const payload = JSON.parse(atob(jwt.split('.')[1]));
const expirationTime = payload.exp * 1000; // Convert to milliseconds
return Date.now() >= expirationTime;
} catch (error) {
console.error("Failed to decode JWT:", error);
return true; // Treat as expired if there's an error
}
}
export const useAuthStore = defineStore('auth', { export const useAuthStore = defineStore('auth', {
state: () => ({ state: () => ({
jwt: localStorage.getItem('jwt') || null, jwt: localStorage.getItem('jwt') || null,
}), }),
getters: { getters: {
isLoggedIn: (state) => !!state.jwt, isLoggedIn: (state) => {
if (state.jwt) {
return !isJwtExpired(state.jwt);
}
return false;
},
isExpired: (state) => {
if (state.jwt) {
return isJwtExpired(state.jwt);
}
return false;
},
id: (state) => { id: (state) => {
if (state.jwt) { if (state.jwt) {
try { try {