При разработке современных одностраничных приложений (SPA) с использованием Vue.js одной из ключевых задач является корректное управление состоянием аутентификации пользователя. Vue Router предоставляет гибкие инструменты для реализации защищённых маршрутов и контроля доступа.
Навигационные охранники позволяют перехватывать переходы между
маршрутами и выполнять проверки перед их выполнением. Для управления
доступом чаще всего используется глобальный охранник
beforeEach:
import { createRouter, createWebHistory } from 'vue-router';
import Home from './components/Home.vue';
import Dashboard from './components/Dashboard.vue';
import Login from './components/Login.vue';
import { isAuthenticated } from './auth'; // функция проверки аутентификации
const routes = [
{ path: '/', component: Home },
{ path: '/login', component: Login },
{ path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isAuthenticated()) {
next('/login');
} else {
next();
}
});
export default router;
Ключевой момент — использование свойства
meta.requiresAuth. Это позволяет централизованно
маркировать маршруты, которые требуют проверки состояния
аутентификации.
Для проверки аутентификации обычно применяются токены, хранящиеся в
localStorage, sessionStorage или
Vuex/Pinia.
Пример использования Pinia для хранения токена:
import { defineStore } from 'pinia';
export const useAuthStore = defineStore('auth', {
state: () => ({
token: localStorage.getItem('token') || null,
}),
getters: {
isAuthenticated: (state) => !!state.token,
},
actions: {
login(token) {
this.token = token;
localStorage.setItem('token', token);
},
logout() {
this.token = null;
localStorage.removeItem('token');
},
},
});
Связка Pinia и Vue Router позволяет делать проверку состояния аутентификации внутри охранников:
import { useAuthStore } from './stores/auth';
router.beforeEach((to, from, next) => {
const auth = useAuthStore();
if (to.meta.requiresAuth && !auth.isAuthenticated) {
next('/login');
} else {
next();
}
});
Иногда необходимо ограничить доступ к определённым компонентам, даже
если пользователь смог попасть на страницу через обход URL. Для этого в
компонентах можно использовать beforeRouteEnter и
beforeRouteUpdate:
export default {
beforeRouteEnter(to, from, next) {
const auth = useAuthStore();
if (!auth.isAuthenticated) {
next('/login');
} else {
next();
}
},
beforeRouteUpdate(to, from, next) {
const auth = useAuthStore();
if (!auth.isAuthenticated) {
next('/login');
} else {
next();
}
},
};
Эти хуки обеспечивают контроль на уровне отдельного компонента, что полезно для динамических маршрутов.
Для предотвращения сброса состояния при перезагрузке страницы важно
синхронизировать Vuex или Pinia с localStorage:
import { watch } from 'vue';
import { useAuthStore } from './stores/auth';
const auth = useAuthStore();
watch(
() => auth.token,
(newToken) => {
if (newToken) {
localStorage.setItem('token', newToken);
} else {
localStorage.removeItem('token');
}
}
);
Это гарантирует, что пользователь останется авторизованным после обновления страницы.
Для поддержания безопасности стоит отслеживать срок действия токена. Один из способов — проверка JWT:
import jwtDecode from 'jwt-decode';
import { useAuthStore } from './stores/auth';
export function isAuthenticated() {
const auth = useAuthStore();
if (!auth.token) return false;
try {
const { exp } = jwtDecode(auth.token);
return Date.now() < exp * 1000;
} catch {
auth.logout();
return false;
}
}
Такой подход предотвращает доступ по просроченному токену и позволяет автоматически перенаправлять пользователя на страницу входа.
Использование meta и охранников позволяет реализовать
уровни доступа:
const routes = [
{ path: '/admin', component: Admin, meta: { requiresAuth: true, role: 'admin' } },
{ path: '/profile', component: Profile, meta: { requiresAuth: true, role: 'user' } },
];
router.beforeEach((to, from, next) => {
const auth = useAuthStore();
if (to.meta.requiresAuth) {
if (!auth.isAuthenticated) return next('/login');
if (to.meta.role && auth.role !== to.meta.role) return next('/');
}
next();
});
Это позволяет строить сложные системы контроля доступа без дублирования логики проверки в компонентах.
localStorage или sessionStorage.beforeEach используются для
глобальной проверки аутентификации.beforeRouteEnter и beforeRouteUpdate
защищают отдельные компоненты.meta маршрута позволяет управлять доступом по
ролям и уровням.Такой подход обеспечивает надёжное управление состоянием аутентификации и интеграцию с маршрутизацией Vue Router, создавая безопасное и масштабируемое SPA.