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,
meta: {
showInNav: false,
navName: '個人資料'
navName: '個人資料',
requiresAuth: true
}
},
{
@@ -71,7 +72,8 @@ const routes = [
meta: {
keepAlive: true,
showInNav: true,
navName: '每日金句'
navName: '每日金句',
requiresAuth: true
}
}
];
@@ -84,8 +86,29 @@ const router = createRouter({
export function unauthRedirectToLogin() {
const auth = useAuthStore();
auth.clearJwt();
alert('Your session has expired. Redirecting to login.');
alert('您的登入驗證已過期。將重新導向至登入頁面。');
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;
+25 -1
View File
@@ -1,11 +1,35 @@
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', {
state: () => ({
jwt: localStorage.getItem('jwt') || null,
}),
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) => {
if (state.jwt) {
try {