Middleware и авторизация
Middleware выполняется до рендера страницы. Полезно для авторизации, редиректов, A/B-тестов.
Создание
middleware.ts в корне проекта (рядом с app/):
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
return NextResponse.next();
}
Matcher
Middleware применяется ко всем роутам. Ограничь:
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*'],
};
Или исключи:
export const config = {
matcher: ['/((?!api|_next/static|favicon.ico).*)'],
};
Редирект
export function middleware(request: NextRequest) {
if (!request.cookies.has('token')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
Rewrite
Меняет URL без редиректа:
return NextResponse.rewrite(new URL('/dashboard', request.url));
Заголовки
const response = NextResponse.next();
response.headers.set('X-Custom', 'value');
return response;
Cookies
const token = request.cookies.get('token')?.value;
const response = NextResponse.next();
response.cookies.set('visited', 'true', { httpOnly: true });
return response;
Проверка авторизации
import { verifyToken } from '@/lib/auth';
export async function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value;
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
const user = await verifyToken(token);
if (!user) {
return NextResponse.redirect(new URL('/login', request.url));
}
const response = NextResponse.next();
response.headers.set('X-User-Id', String(user.id));
return response;
}
export const config = {
matcher: ['/dashboard/:path*'],
};
Роли
export function middleware(request: NextRequest) {
const role = request.cookies.get('role')?.value;
if (request.nextUrl.pathname.startsWith('/admin') && role !== 'admin') {
return NextResponse.redirect(new URL('/forbidden', request.url));
}
return NextResponse.next();
}
Аутентификация в Server Actions
Middleware защищает страницы, но не API. Проверяй внутри:
'use server';
import { cookies } from 'next/headers';
export async function deletePost(id: number) {
const token = (await cookies()).get('token')?.value;
const user = await verifyToken(token);
if (!user) throw new Error('Unauthorized');
// проверка прав
}
Сессии
Next.js не имеет встроенных сессий. Варианты:
- Cookies — JWT или session ID
- Сторонние библиотеки — Auth.js, Lucia
- Свой слой — Prisma + cookies
Auth.js
npm install next-auth@beta
auth.ts:
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [GitHub],
});
app/api/auth/[...nextauth]/route.ts:
import { handlers } from '@/auth';
export const { GET, POST } = handlers;
Использование:
import { auth } from '@/auth';
const session = await auth();
if (!session) redirect('/login');
Защита роутов
// app/dashboard/layout.tsx
import { auth } from '@/auth';
import { redirect } from 'next/navigation';
export default async function Layout({ children }) {
const session = await auth();
if (!session) redirect('/login');
return <>{children}</>;
}
Итоги
middleware.tsв корнеmatcherдля ограниченияredirect,rewrite,next- Cookies и заголовки
- Middleware не защищает API — проверяй внутри
- Auth.js для полноценной аутентификации