Расширение сессии Auth.js
Auth.js (ранее NextAuth.js) — это популярная библиотека для аутентификации в Next.js-приложениях. Она предоставляет простой и гибкий способ настройки аутентификации с поддержкой множества провайдеров (например, Google, GitHub, Yandex и других). Однако часто возникает необходимость расширить стандартную сессию, чтобы добавить в нее дополнительные данные пользователя, такие как роль, дата создания аккаунта или другие поля. В этой статье мы рассмотрим, как расширить сессию в Auth.js, используя пример кода.
Зачем расширять сессию?
По умолчанию Auth.js предоставляет базовые данные о пользователе в сессии, такие как name
, email
и image
. Однако в реальных приложениях часто требуется хранить и использовать дополнительные данные, например:
- Роль пользователя (администратор, модератор, пользователь).
- Идентификатор пользователя в базе данных.
- Дата создания и обновления аккаунта.
- Другие пользовательские поля.
Расширение сессии позволяет получить доступ к этим данным на клиенте и сервере, что упрощает разработку и улучшает функциональность приложения.
Пример расширения сессии в Auth.js
Рассмотрим пример кода, который расширяет сессию в Auth.js, добавляя в нее дополнительные поля пользователя.
1. Настройка NextAuth.js
Для начала настроим NextAuth.js с использованием Prisma в качестве адаптера. PrismaAdapter позволяет интегрировать Auth.js с базой данных, где хранятся данные пользователей.
import NextAuth, { type DefaultSession } from "next-auth";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { UserRole } from "@prisma/client";
import { prisma } from "@/prisma";
import type { Provider } from "next-auth/providers";
import Yandex from "next-auth/providers/yandex";
import GitHub from "next-auth/providers/github";
2. Расширение интерфейса сессии
Чтобы добавить дополнительные поля в сессию, необходимо расширить интерфейс Session
из модуля next-auth
. В данном примере мы добавляем поля id
, role
, createdAt
и updatedAt
.
declare module "next-auth" {
interface Session {
user: {
id: string;
name: string;
email: string;
emailVerified: string | null;
image: string | null;
role: UserRole;
createdAt: Date;
updatedAt: Date;
} & DefaultSession["user"];
}
}
3. Настройка провайдеров
Определяем провайдеры аутентификации. В данном примере используются Yandex и GitHub.
const providers: Provider[] = [Yandex, GitHub];
export const providerMap = providers
.map((provider) => {
if (typeof provider === "function") {
const providerData = provider();
return { id: providerData.id, name: providerData.name };
} else {
return { id: provider.id, name: provider.name };
}
})
.filter((provider) => provider.id !== "credentials");
4. Конфигурация NextAuth.js
Настраиваем NextAuth.js, используя PrismaAdapter и добавляем кастомный колбэк session
, чтобы включить дополнительные данные пользователя в сессию.
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers,
pages: {
signIn: "/login",
error: "/error",
},
callbacks: {
session({ session, user }) {
session.user.id = user.id;
session.user.role = user.role;
session.user.createdAt = user.createdAt;
session.user.updatedAt = user.updatedAt;
return session;
},
},
});
5. Использование расширенной сессии
Теперь, когда сессия расширена, вы можете использовать дополнительные данные пользователя в своих компонентах и API-роутах. Например:
import { auth } from "@/auth";
export default async function Profile() {
const session = await auth();
if (!session) {
return <div>Необходимо авторизоваться</div>;
}
return (
<div>
<h1>Профиль</h1>
<p>Имя: {session.user.name}</p>
<p>Роль: {session.user.role}</p>
<p>Дата создания: {session.user.createdAt.toLocaleDateString()}</p>
</div>
);
}
Преимущества расширения сессии
-
Доступ к дополнительным данным
Расширение сессии позволяет получить доступ к данным, которые не включены в стандартную сессию Auth.js. -
Упрощение разработки
Вам не нужно делать дополнительные запросы к базе данных для получения данных пользователя, так как они уже доступны в сессии. -
Гибкость
Вы можете добавлять любые пользовательские поля, которые необходимы для вашего приложения.
6. Практическое применение расширенной сессии
Расширенная сессия может быть полезна в различных сценариях. Например:
-
Ролевая модель доступа
Если в вашем приложении есть разные роли пользователей (администратор, модератор, обычный пользователь), вы можете использовать полеrole
для управления доступом к определенным страницам или функциям.import { auth } from "@/auth"; export default async function AdminPage() { const session = await auth(); if (!session || session.user.role !== "ADMIN") { return <div>Доступ запрещен</div>; } return ( <div> <h1>Административная панель</h1> <p>Добро пожаловать, {session.user.name}!</p> </div> ); }
-
Отображение информации о пользователе
Вы можете использовать расширенные данные для отображения информации о пользователе на странице профиля.import { auth } from "@/auth"; export default async function ProfilePage() { const session = await auth(); if (!session) { return <div>Необходимо авторизоваться</div>; } return ( <div> <h1>Профиль</h1> <p>Имя: {session.user.name}</p> <p>Email: {session.user.email}</p> <p>Роль: {session.user.role}</p> <p>Дата регистрации: {session.user.createdAt.toLocaleDateString()}</p> </div> ); }
-
Логика на основе даты создания аккаунта
Если вам нужно реализовать логику, зависящую от даты создания аккаунта (например, показывать специальное сообщение для новых пользователей), вы можете использовать полеcreatedAt
.import { auth } from "@/auth"; export default async function WelcomeMessage() { const session = await auth(); if (!session) { return null; } const isNewUser = new Date().getTime() - session.user.createdAt.getTime() < 7 * 24 * 60 * 60 * 1000; // Проверяем, что пользователь зарегистрирован менее недели назад if (isNewUser) { return ( <div>Добро пожаловать! Мы рады видеть вас в нашем сообществе.</div> ); } return null; }
7. Безопасность и лучшие практики
При работе с расширенной сессией важно учитывать следующие аспекты безопасности:
-
Не передавайте чувствительные данные
Убедитесь, что вы не включаете в сессию данные, которые могут быть скомпрометированы (например, пароли или токены). -
Используйте HTTPS
Все данные сессии передаются между клиентом и сервером, поэтому важно использовать HTTPS для защиты от перехвата данных. -
Ограничивайте доступ к данным
Если вы используете ролевую модель, убедитесь, что доступ к данным ограничен в зависимости от роли пользователя. -
Регулярно обновляйте зависимости
Auth.js и связанные библиотеки (например, Prisma) регулярно обновляются. Убедитесь, что вы используете последние версии для получения исправлений уязвимостей.