feat: auth route guard
This commit is contained in:
+26
-3
@@ -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
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user