Аутентификация и авторизация

Аутентификация и авторизация являются ключевыми аспектами безопасности веб-приложений. В контексте Vue.js они реализуются через комбинацию клиентской логики и взаимодействия с сервером.


Аутентификация: проверка пользователя

Аутентификация — процесс проверки подлинности пользователя. В Vue.js чаще всего используется следующий подход:

  1. Форма входа: создается компонент LoginForm.vue, который содержит поля для ввода логина и пароля, а также кнопку отправки данных на сервер.
<template>
  <form @submit.prevent="login">
    <input v-model="email" type="email" placeholder="Email" required />
    <input v-model="password" type="password" placeholder="Пароль" required />
    <button type="submit">Войти</button>
  </form>
</template>

<script>
export default {
  data() {
    return {
      email: '',
      password: ''
    };
  },
  methods: {
    async login() {
      try {
        const response = await fetch('/api/login', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email: this.email, password: this.password })
        });
        const data = await response.json();
        if (response.ok) {
          localStorage.setItem('token', data.token);
          this.$router.push('/dashboard');
        } else {
          console.error(data.message);
        }
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>

Ключевые моменты:

  • Использование v-model для двусторонней привязки данных.
  • Асинхронный метод login для отправки запроса на сервер.
  • Хранение JWT или другого токена в localStorage для последующих запросов.

Авторизация: проверка прав доступа

Авторизация определяет, какие действия разрешены пользователю после входа в систему. В Vue.js авторизация обычно реализуется через:

  1. Роутер Guards: защита маршрутов на основе токена или роли пользователя.
import { createRouter, createWebHistory } from 'vue-router';
import Dashboard from './components/Dashboard.vue';
import Login from './components/LoginForm.vue';

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

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

router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token');
  if (to.meta.requiresAuth && !token) {
    next('/login');
  } else {
    next();
  }
});

export default router;

Основные принципы:

  • Использование мета-полей маршрутов для обозначения защищенных страниц.
  • Проверка наличия токена перед переходом.
  • Перенаправление неаутентифицированного пользователя на страницу входа.
  1. Компоненты с условным рендерингом: отображение элементов интерфейса в зависимости от роли пользователя.
<template>
  <div>
    <button v-if="userRole === 'admin'">Админ-панель</button>
    <button v-if="userRole === 'user'">Профиль</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userRole: ''
    };
  },
  created() {
    const token = localStorage.getItem('token');
    if (token) {
      const payload = JSON.parse(atob(token.split('.')[1]));
      this.userRole = payload.role;
    }
  }
};
</script>

Хранение и управление токенами

Для безопасной работы с токенами используются следующие методы:

  • localStorage: простое хранение токена, подходит для SPA, но уязвимо к XSS-атакам.
  • Vuex/Pinia: хранение токена в состоянии приложения для реактивного доступа.
  • HTTP-only cookies: безопасное хранение токена на сервере, предотвращает XSS, но требует серверной поддержки.

Пример использования Pinia для управления токеном:

import { defineStore } from 'pinia';

export const useAuthStore = defineStore('auth', {
  state: () => ({
    token: localStorage.getItem('token') || ''
  }),
  actions: {
    setToken(token) {
      this.token = token;
      localStorage.setItem('token', token);
    },
    logout() {
      this.token = '';
      localStorage.removeItem('token');
    }
  }
});

Работа с защищенными API

Для взаимодействия с сервером используют токены в заголовках Authorization:

async function fetchData() {
  const token = localStorage.getItem('token');
  const response = await fetch('/api/protected', {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });
  return await response.json();
}

Особенности:

  • Каждый запрос к защищенному API включает токен.
  • Сервер проверяет подлинность токена и возвращает данные только авторизованным пользователям.
  • Ошибки авторизации обрабатываются через редирект на страницу входа или уведомление пользователя.

Обновление и истечение токена

Для SPA важно обрабатывать истечение срока действия токена. Общая схема:

  1. Проверка токена перед каждым защищенным запросом.
  2. Если токен истек — попытка обновления через refresh-token.
  3. Если обновление невозможно — выход пользователя из системы.

Пример с использованием axios:

import axios from 'axios';

const api = axios.create({
  baseURL: '/api'
});

api.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

api.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

Рекомендации по безопасности

  • Использовать HTTPS для передачи токенов и паролей.
  • Минимизировать хранение токенов в клиентском коде.
  • Ограничивать права доступа на уровне сервера.
  • Обновлять зависимости Vue.js и библиотек безопасности.

Эти механизмы обеспечивают надежную аутентификацию и авторизацию, позволяют управлять доступом к ресурсам и защищают приложение от несанкционированного использования.