Пошук уроків, статей та іншого контенту
Реалізуєте ранню перевірку доступу через Middleware або Proxy та налаштуєте перенаправлення користувачів.
Middleware — це код, який виконується перед обробкою запиту до сторінки або API-маршруту. Він може:
перевірити cookie або заголовки;
перенаправити користувача;
пропустити запит далі;
переписати адресу запиту;
застосувати логіку лише до певних маршрутів.
У Next.js 16 назву Middleware було змінено на Proxy:
файл proxy.ts;
функція proxy;
у попередніх версіях — файл middleware.ts і функція middleware.
Механізм і призначення залишаються подібними: перевірити запит якомога раніше, до рендерингу сторінки.
Припустимо, що всі маршрути всередині /dashboard доступні лише авторизованим користувачам. Ознакою авторизації буде cookie session.
Створіть файл proxy.ts у корені проєкту або всередині src:
import { NextRequest, NextResponse } from "next/server";
export function proxy(request: NextRequest) {
const session = request.cookies.get("session")?.value;
if (!session) {
const loginUrl = new URL("/login", request.url);
// Після входу можна повернути користувача на початкову сторінку
const nextPath =
request.nextUrl.pathname + request.nextUrl.search;
loginUrl.searchParams.set("next", nextPath);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};Тепер запит до /dashboard, /dashboard/settings або /dashboard/orders/123 спочатку пройде через proxy.
Якщо cookie session немає:
Proxy зупиняє подальшу обробку запиту.
Користувач отримує перенаправлення на /login.
До адреси входу додається параметр next.
Якщо cookie існує, виконується:
return NextResponse.next();Це дозволяє запиту продовжити обробку.
matcherВластивість config.matcher визначає, для яких маршрутів запускається Proxy:
export const config = {
matcher: ["/dashboard/:path*"],
};Шаблон :path* означає:
/dashboard;
/dashboard/settings;
/dashboard/orders/123;
будь-який інший вкладений маршрут.
Можна вказати кілька шаблонів:
export const config = {
matcher: ["/dashboard/:path*", "/account/:path*"],
};У такому разі одна перевірка застосовуватиметься до приватної частини панелі та особистого кабінету.
Краще обмежувати Proxy через matcher, а не запускати його для кожного запиту:
export const config = {
matcher: ["/dashboard/:path*"],
};Це робить поведінку зрозумілішою та не змушує перевіряти публічні сторінки.
Параметр next зберігає маршрут, який користувач хотів відкрити. Наприклад:
/login?next=%2Fdashboard%2FsettingsПісля успішної авторизації сервер може створити cookie та перенаправити користувача назад на /dashboard/settings.
Спрощений приклад Route Handler для демонстрації:
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const requestedPath = request.nextUrl.searchParams.get("next");
const nextPath =
requestedPath &&
requestedPath.startsWith("/") &&
!requestedPath.startsWith("//")
? requestedPath
: "/dashboard";
const response = NextResponse.redirect(
new URL(nextPath, request.url),
);
response.cookies.set("session", "demo-session", {
httpOnly: true,
sameSite: "lax",
secure: process.env.NODE_ENV === "production",
path: "/",
});
return response;
}Цей файл можна розмістити за адресою:
app/api/demo-login/route.tsПісля відкриття /api/demo-login?next=/dashboard/settings буде встановлено cookie та виконано перенаправлення на потрібний маршрут.
Значення
demo-sessionвикористовується лише для демонстрації. У реальному застосунку cookie має містити сесію або підписаний токен, створений справжньою системою автентифікації.
Якщо проєкт використовує версію Next.js, де ще застосовується Middleware, потрібно використовувати файл middleware.ts:
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
const session = request.cookies.get("session")?.value;
if (!session) {
const loginUrl = new URL("/login", request.url);
loginUrl.searchParams.set(
"next",
request.nextUrl.pathname + request.nextUrl.search,
);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};Не потрібно одночасно створювати middleware.ts і proxy.ts для однієї перевірки. Вибирайте назву відповідно до версії Next.js у проєкті.
Перевірка наявності cookie:
const session = request.cookies.get("session")?.value;
if (!session) {
// Перенаправлення
}показує лише, що cookie існує. Вона не доводить, що:
сесія справжня;
токен не підроблений;
сесія не завершилася;
користувач має потрібні права;
користувач може працювати саме з цим ресурсом.
У реальному застосунку Proxy має перевіряти сесію або підписаний токен за допомогою вашої системи автентифікації. Для складних перевірок доступу можна передати запит далі, а остаточну перевірку виконати на сервері.
Proxy не повинен бути єдиним рівнем захисту. Перевірки також мають виконуватися в:
Server Actions;
Route Handlers;
серверних функціях, які повертають приватні дані;
коді, що змінює дані.
Наприклад, навіть якщо Proxy захищає /dashboard, API-маршрут також повинен самостійно перевіряти користувача. API можна викликати безпосередньо, не відкриваючи сторінку панелі.
Для перенаправлення використовується:
return NextResponse.redirect(new URL("/login", request.url));Це відповідає HTTP-перенаправленню, і браузер виконає новий запит до /login.
Для пропуску запиту використовується:
return NextResponse.next();Типовий алгоритм виглядає так:
export function proxy(request: NextRequest) {
const isAuthenticated = Boolean(
request.cookies.get("session")?.value,
);
if (!isAuthenticated) {
return NextResponse.redirect(
new URL("/login", request.url),
);
}
return NextResponse.next();
}Proxy має повернути один із результатів для кожного запиту, який він обробляє:
NextResponse.next() — продовжити запит;
NextResponse.redirect(...) — перенаправити користувача;
інший об’єкт NextResponse — змінити відповідь або виконати rewrite.
Якщо Proxy запускається для кожного маршруту, він може перевіряти навіть статичні файли, сторінку входу та публічні сторінки.
Використовуйте вузький matcher:
export const config = {
matcher: ["/dashboard/:path*"],
};Якщо Proxy перенаправляє на /login, але сам також обробляє /login, можна отримати нескінченне перенаправлення.
Обмежуйте Proxy приватними маршрутами через matcher. Наприклад, шаблон /dashboard/:path* не зачіпає /login.
Користувач може вручну створити cookie з будь-яким значенням. Перевіряйте дійсність сесії або підпис токена, а не лише його наявність.
Захист сторінки не захищає автоматично API. Кожен серверний endpoint, який повертає або змінює приватні дані, повинен перевіряти доступ самостійно.
nextНе можна без перевірки перенаправляти користувача на довільне значення з query-параметра. Дозволяйте лише внутрішні шляхи поточного застосунку:
const isInternalPath =
nextPath.startsWith("/") && !nextPath.startsWith("//");Це запобігає перенаправленню на зовнішній сайт.
У Next.js 16 рання перевірка запитів реалізується через proxy.ts.
У старіших версіях використовується middleware.ts.
matcher визначає маршрути, для яких запускається перевірка.
NextResponse.redirect() перенаправляє неавторизованого користувача.
NextResponse.next() дозволяє запиту продовжити обробку.
Cookie можна використати як ознаку сесії, але її потрібно перевіряти криптографічно або через серверне сховище.
Proxy покращує маршрутизацію, але не замінює перевірки доступу в API та серверній логіці.
Параметр next дає змогу повернути користувача на початковий маршрут після входу.