Сессии и аутентификация
Введение
Здесь настраивается аутентификация в полноценном Nuxt-приложении с помощью Nuxt Auth Utils — удобные утилиты для сессии на клиенте и сервере.
Модуль хранит данные сессии в защищённых запечатанных cookie, отдельная база для сессий не нужна.
Установка nuxt-auth-utils
Установите модуль nuxt-auth-utils через CLI Nuxt.
npx nuxt module add auth-utils
nuxt-auth-utils в зависимости и пропишет модуль в секции modules файла nuxt.config.Ключ шифрования cookie
Так как nuxt-auth-utils использует запечатанные cookie, сессионные cookie шифруются секретом из переменной окружения NUXT_SESSION_PASSWORD.
.env автоматически.NUXT_SESSION_PASSWORD=a-random-password-with-at-least-32-characters
API-маршрут входа
В этом рецепте создаётся простой API-маршрут для входа по статическим данным.
Создайте маршрут /api/login, принимающий POST с email и паролем в теле запроса.
import { z } from 'zod'
const bodySchema = z.object({
email: z.string().email(),
password: z.string().min(8),
})
export default defineEventHandler(async (event) => {
const { email, password } = await readValidatedBody(event, bodySchema.parse)
if (email === 'admin@admin.com' && password === 'iamtheadmin') {
// сохраняем сессию пользователя в cookie
// этот серверный хелпер подхватывается автоимпортом модуля auth-utils
await setUserSession(event, {
user: {
name: 'John Doe',
},
})
return {}
}
throw createError({
statusCode: 401,
message: 'Неверные учётные данные',
})
})
zod в проект (например, npm i zod).Страница входа
Модуль предоставляет Vue-композабл для проверки, авторизован ли пользователь:
<script setup>
const { loggedIn, session, user, clear, fetch } = useUserSession()
</script>
Создайте страницу входа с формой, отправляющей данные на маршрут /api/login.
<script setup lang="ts">
const { loggedIn, user, fetch: refreshSession } = useUserSession()
const credentials = reactive({
email: '',
password: '',
})
async function login () {
try {
await $fetch('/api/login', {
method: 'POST',
body: credentials,
})
// обновляем сессию на клиенте и переходим на главную
await refreshSession()
await navigateTo('/')
} catch {
alert('Неверные учётные данные')
}
}
</script>
<template>
<form @submit.prevent="login">
<input
v-model="credentials.email"
type="email"
placeholder="Эл. почта"
>
<input
v-model="credentials.password"
type="password"
placeholder="Пароль"
>
<button type="submit">
Войти
</button>
</form>
</template>
Защита API-маршрутов
Защита серверных маршрутов нужна, чтобы данные были в безопасности. Клиентский middleware удобен пользователю, но без проверки на сервере данные всё равно можно запросить. Любые маршруты с чувствительными данными должны отвечать 401, если пользователь не вошёл.
В auth-utils есть requireUserSession — гарантирует, что у запроса есть валидная сессия.
Пример маршрута /api/user/stats, доступного только авторизованным:
export default defineEventHandler(async (event) => {
// убеждаемся, что пользователь авторизован
// при отсутствии валидной сессии будет выброшена ошибка 401
const { user } = await requireUserSession(event)
// TODO: получить статистику по пользователю
return {}
})
Защита маршрутов приложения
Серверный маршрут защищает данные, но без дополнительных мер неавторизованный пользователь может открыть, например, /users и увидеть странное поведение. Стоит добавить клиентский middleware, чтобы на клиенте перенаправлять на страницу входа.
В nuxt-auth-utils для этого есть композабл useUserSession: проверяем loggedIn и при необходимости редиректим.
Создайте middleware в каталоге /middleware. В отличие от сервера, клиентский middleware не применяется ко всем маршрутам автоматически — его нужно явно указать.
export default defineNuxtRouteMiddleware(() => {
const { loggedIn } = useUserSession()
// если не авторизован — на страницу входа
if (!loggedIn.value) {
return navigateTo('/login')
}
})
Главная страница
С middleware можно защитить домашнюю страницу с информацией о пользователе: если не авторизован — редирект на /login.
Подключите middleware через definePageMeta.
<script setup lang="ts">
definePageMeta({
middleware: ['authenticated'],
})
const { user, clear: clearSession } = useUserSession()
async function logout () {
await clearSession()
await navigateTo('/login')
}
</script>
<template>
<div>
<h1>Добро пожаловать, {{ user.name }}</h1>
<button @click="logout">
Выйти
</button>
</div>
</template>
Добавлена кнопка выхода: очищает сессию и ведёт на /login.
Заключение
Настроены базовая аутентификация и сессии, защищены чувствительные маршруты на сервере и клиенте — доступ только у вошедших пользователей.
Дальше можно:
- Подключить один из 20+ OAuth-провайдеров
- Добавить базу пользователей: Nitro SQL Database или NuxtHub SQL Database
- Реализовать регистрацию по email и паролю с хэшированием паролей
- Включить WebAuthn / Passkeys
Полный пример приложения с OAuth, базой и CRUD — в открытом репозитории atidone.