Авторизация и защита маршрутов во Vue 3: токены, Axios и route guards

1. Что такое авторизация

Авторизация — это процесс проверки прав пользователя для доступа к ресурсам приложения.
Чаще всего она реализуется через JWT-токены (JSON Web Token).
Пользователь вводит логин и пароль → сервер проверяет данные → если всё верно, он возвращает токен доступа.

Этот токен хранится у клиента (например, в localStorage) и прикрепляется к каждому запросу.
Сервер, получая токен, проверяет его подлинность и срок действия, разрешая или запрещая доступ к ресурсам.

2. Настройка Axios и авторизационного запроса

Чтобы централизовать работу с сервером, создадим модуль api.js. В нём мы настроим базовый URL, перехватчики запросов и маршруты API.

// src/api.js
import axios from 'axios'
import { isTokenExpired } from '@/utils/token'
import { logoutUser } from '@/services/auth'

export const API_BASE_URL = 'https://example.com/api'

export const api = axios.create({
  baseURL: API_BASE_URL,
})

// эндпоинты приложения
export const API_ENDPOINTS = {
  ARTICLES: '/articles',
  USERS: '/users',
  LOGIN: '/login',
  LOGOUT: '/logout',
}

// перехватчик запроса: добавляем токен в заголовок, если он есть
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token')
  if (token) {
    if (isTokenExpired(token)) {
      logoutUser()
      window.location.href = '/login'
      throw new axios.Cancel('Token expired')
    }
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// перехватчик ответа: если сервер вернул 401, выполняем logout
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      logoutUser()
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

3. Проверка срока действия токена

Создадим утилиту token.js, которая проверяет, не истёк ли срок действия JWT.
Для этого расшифруем payload токена и сравним время истечения (exp) с текущим временем.

// src/utils/token.js
export function isTokenExpired(token) {
  if (!token) return true
  try {
    const payload = JSON.parse(atob(token.split('.')[1]))
    const currentTime = Math.floor(Date.now() / 1000)
    return payload.exp < currentTime
  } catch (e) {
    return true
  }
}

4. Создание функций для авторизации и выхода

Опишем функции loginUser и logoutUser в отдельном модуле auth.js.

// src/services/auth.js
import { api, API_ENDPOINTS } from '@/api'

export async function loginUser(credentials) {
  const { data } = await api.post(API_ENDPOINTS.LOGIN, credentials)
  localStorage.setItem('token', data.token)
  return data
}

export function logoutUser() {
  localStorage.removeItem('token')
}

5. Пример использования в компоненте Login.vue

Простая форма входа, где пользователь вводит email и пароль. После успешного логина мы сохраняем токен и перенаправляем на защищённую страницу /dashboard.

<!-- src/views/Login.vue -->
<template>
  <div class="login">
    <h1>Вход</h1>
    <form @submit.prevent="login">
      <input v-model="email" type="email" placeholder="Email" />
      <input v-model="password" type="password" placeholder="Пароль" />
      <button type="submit">Войти</button>
    </form>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { loginUser } from '@/services/auth'

const email = ref('')
const password = ref('')
const router = useRouter()

const login = async () => {
  try {
    await loginUser({ email: email.value, password: password.value })
    router.push('/dashboard')
  } catch (error) {
    alert('Ошибка авторизации!')
  }
}
</script>

6. Route Guards (Защита маршрутов)

Navigation Guards — это механизм Vue Router, который позволяет перехватывать переходы между страницами и выполнять логику проверки.

Мы проверяем, есть ли токен и не истёк ли он. Если токен недействителен — выполняем logout и перенаправляем пользователя на страницу входа.

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/Login.vue'
import Dashboard from '@/views/Dashboard.vue'
import { isTokenExpired } from '@/utils/token'
import { logoutUser } from '@/services/auth'

const routes = [
  { path: '/login', component: Login },
  {
    path: '/dashboard',
    component: Dashboard,
    meta: { requiresAuth: true },
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

// глобальный guard
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  const isAuthenticated = !!token && !isTokenExpired(token)

  if (to.meta.requiresAuth && !isAuthenticated) {
    logoutUser()
    next('/login')
  } else {
    next()
  }
})

export default router

7. Выход из системы (Logout)

Кнопка «Выйти» просто удаляет токен и перенаправляет пользователя обратно на страницу входа.

<!-- src/components/LogoutButton.vue -->
<template>
  <button @click="logout">Выйти</button>
</template>

<script setup>
import { useRouter } from 'vue-router'
import { logoutUser } from '@/services/auth'

const router = useRouter()

const logout = () => {
  logoutUser()
  router.push('/login')
}
</script>

💡 Итого

  • Разобрали, что такое авторизация и зачем нужны токены.

  • Создали модуль api.js с Axios и перехватчиками для токена.

  • Реализовали функции логина и логаута.

  • Добавили проверку срока действия токена с автоматическим выходом.

  • Настроили route guard, чтобы защищать маршруты.

  • Создали компонент Logout, который выполняет выход из системы.

Таким образом, приложение теперь может:

  • Авторизовать пользователя;

  • Хранить токен в localStorage;

  • Проверять срок его действия;

  • Автоматически выполнять logout при истечении токена или ошибке 401.