Расширение сессии 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>
  );
}

Преимущества расширения сессии

  1. Доступ к дополнительным данным
    Расширение сессии позволяет получить доступ к данным, которые не включены в стандартную сессию Auth.js.

  2. Упрощение разработки
    Вам не нужно делать дополнительные запросы к базе данных для получения данных пользователя, так как они уже доступны в сессии.

  3. Гибкость
    Вы можете добавлять любые пользовательские поля, которые необходимы для вашего приложения.

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. Безопасность и лучшие практики

При работе с расширенной сессией важно учитывать следующие аспекты безопасности:

  1. Не передавайте чувствительные данные
    Убедитесь, что вы не включаете в сессию данные, которые могут быть скомпрометированы (например, пароли или токены).

  2. Используйте HTTPS
    Все данные сессии передаются между клиентом и сервером, поэтому важно использовать HTTPS для защиты от перехвата данных.

  3. Ограничивайте доступ к данным
    Если вы используете ролевую модель, убедитесь, что доступ к данным ограничен в зависимости от роли пользователя.

  4. Регулярно обновляйте зависимости
    Auth.js и связанные библиотеки (например, Prisma) регулярно обновляются. Убедитесь, что вы используете последние версии для получения исправлений уязвимостей.

nextjsauthjsprisma
Обсудим ваш проект?
Не ждите идеального момента или подходящего времени — начинайте прямо сейчас! Свяжитесь со мной, и я помогу воплотить ваши идеи в реальность.