1. Для чего нужна сессия в layout/page?
В современных приложениях на Next.js сессия пользователя — это не просто “галочка” в чек-листе. Это основа для:
- отображения персональной информации (например, приветствия по имени),
- ограничения доступа к страницам или разделам сайта,
- динамического формирования меню, кнопок “Войти/Выйти” и т.д.
Особенно удобно получать сессию в файлах layout.tsx или page.tsx, потому что они — входная точка для всего UI на уровне страницы или раздела. Здесь можно “протянуть” данные о пользователе во все дочерние компоненты.
Вспоминаем что возвращает функция auth():
В Next.js 15 с App Router (папка app/) вы можете получать сессию на сервере с помощью асинхронной функции auth() из next-auth. Она возвращает объект сессии пользователя (или null, если пользователь не авторизован).
Пример сессии:
{
user: {
name: "Иван Иванов",
email: "ivan@example.com",
image: "https://avatar.com/ivan.jpg"
},
expires: "2024-07-01T12:34:56.789Z"
}
2. Получаем сессию в layout.tsx
Давайте разберёмся, как получить и использовать сессию в корневом layout.
Шаг 1. Импортируем функцию auth
// app/layout.tsx
import { auth } from "@/auth"; // путь может отличаться в зависимости от вашей структуры
Важно:
Если вы следуете документации next-auth, функцию auth нужно экспортировать из вашего файла конфигурации next-auth (например, auth.ts или auth.js в корне проекта или в папке lib/).
Шаг 2. Делаем layout асинхронным
Поскольку auth() — асинхронная функция, ваш компонент layout должен быть async:
export default async function RootLayout({ children }) {
const session = await auth();
return (
<html lang="ru">
<body>
{/* Передаём сессию в навигацию, шапку или куда угодно */}
<Header session={session} />
<main>{children}</main>
</body>
</html>
);
}
Шаг 3. Используем session в дочерних компонентах
Создайте, например, компонент Header, который будет показывать имя пользователя и кнопку “Войти/Выйти” в зависимости от того, есть ли сессия.
// components/Header.tsx
export default function Header({ session }) {
return (
<header style={{ padding: 16, borderBottom: "1px solid #eee" }}>
{session?.user ? (
<span>
Привет, {session.user.name}!{" "}
<a href="/api/auth/signout">Выйти</a>
</span>
) : (
<a href="/api/auth/signin">Войти</a>
)}
</header>
);
}
Шутка для разрядки:
Пользователь без сессии — как фронтендер без кофе: вроде бы работает, но удовольствия мало.
3. Получение сессии в page.tsx
Точно так же вы можете получить сессию в любом файле page.tsx, если он асинхронный.
// app/page.tsx
import { auth } from "@/auth";
export default async function HomePage() {
const session = await auth();
return (
<section>
<h1>Главная страница</h1>
{session?.user ? (
<p>Добро пожаловать, {session.user.name}!</p>
) : (
<p>Пожалуйста, <a href="/api/auth/signin">войдите</a> для продолжения.</p>
)}
</section>
);
}
4. Пример: защищаем страницу только для авторизованных
Допустим, у нас есть страница профиля, которую должен видеть только залогиненный пользователь. Как это сделать?
// app/profile/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function ProfilePage() {
const session = await auth();
if (!session?.user) {
// Пользователь не авторизован — отправим его на главную
redirect("/");
}
return (
<div>
<h2>Профиль пользователя</h2>
<p>Имя: {session.user.name}</p>
<p>Email: {session.user.email}</p>
<img src={session.user.image} alt="аватар" width={64} height={64} />
</div>
);
}
Обратите внимание:
Функция redirect() работает только на сервере (то есть в Server Component или в асинхронном обработчике). На клиенте используйте хук useRouter().push().
5. Передача сессии вниз по дереву через пропсы или Context
Если вам нужно “протянуть” сессию глубоко в дерево компонентов, два варианта:
- Передавать через пропсы (как в примере с Header выше).
- Создать React Context и обернуть нужные компоненты.
Пример Context (Server Component):
// lib/SessionContext.tsx
import { createContext } from "react";
export const SessionContext = createContext(null);
// app/layout.tsx
import { SessionContext } from "@/lib/SessionContext";
import { auth } from "@/auth";
export default async function RootLayout({ children }) {
const session = await auth();
return (
<html lang="ru">
<body>
<SessionContext.Provider value={session}>
<Header />
<main>{children}</main>
</SessionContext.Provider>
</body>
</html>
);
}
В дочерних компонентах:
import { useContext } from "react";
import { SessionContext } from "@/lib/SessionContext";
export default function UserInfo() {
const session = useContext(SessionContext);
if (!session?.user) return null;
return <div>Пользователь: {session.user.name}</div>;
}
Важно:
Контекст работает только в Client Components. Если вы хотите использовать session в Client Component, не забудьте добавить 'use client' в начало файла.
6. Как это выглядит в реальном приложении
Вот схема, как данные о сессии “текут” через ваше приложение:
┌────────────┐
│ layout.tsx │
└─────┬──────┘
│ (await auth())
▼
┌────────────┐
│ Header │ ← session через пропсы
└────────────┘
│
▼
┌────────────┐
│ Main │
│ (children)│
└────────────┘
│
▼
┌────────────┐
│ Page │ ← session через пропсы или Context
└────────────┘
7. Типичные ошибки при работе с сессией в layout/page
Ошибка №1: забыли сделать компонент асинхронным.
Если вы используете await auth(), ваш компонент должен быть async. Если забыли — получите ошибку компиляции или “Unexpected token”.
Ошибка №2: неверный импорт функции auth.
Проверьте путь к вашей функции auth. В Next.js 15 структура может быть разной, не всегда это next-auth/react.
Ошибка №3: попытка использовать session в Client Component без передачи через пропсы или Context.
Функция auth() работает только на сервере. Для Client Components прокидывайте session через пропсы или Context.
Ошибка №4: попытка вызвать redirect() на клиенте.
Функция redirect() работает только на сервере. Для клиента используйте хук useRouter.
Ошибка №5: забыли обработать случай, когда session равен null.
Пользователь может быть не авторизован! Не забывайте проверять session?.user перед выводом личной информации.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ