Загрузка…
Загрузка…
Middleware в Next.js — это Edge-функция в корне проекта, которая выполняется до маршрута и может перенаправлять, переписывать URL или добавлять заголовки. Это UX-слой, а не единственная линия защиты.
Файл middleware.ts лежит рядом с app/, а не внутри него. На Edge доступны Web Crypto API (jose), но не Node-модули вроде jsonwebtoken. Оптимистичная проверка JWT в cookie — нормально; реальная авторизация должна повторяться в Server Component или Server Action.
// middleware.ts — root of the project, NOT inside app/
import { NextResponse, type NextRequest } from 'next/server';
import { jwtVerify } from 'jose'; // Web Crypto — works on Edge. `jsonwebtoken` does NOT.
const secret = new TextEncoder().encode(process.env.SESSION_SECRET!);
export async function middleware(req: NextRequest) {
const token = req.cookies.get('session')?.value;
// ✅ Optimistic check only: is there a structurally valid session?
// The real authorization still happens in the page/Server Action.
if (!token) {
const url = new URL('/login', req.url);
url.searchParams.set('from', req.nextUrl.pathname); // preserve intent
return NextResponse.redirect(url);
}
try {
const { payload } = await jwtVerify(token, secret);
const res = NextResponse.next();
// Pass verified claims down — headers are the only channel to the route.
res.headers.set('x-user-id', String(payload.sub));
return res;
} catch {
// Expired/tampered → clear the cookie so we don't redirect-loop.
const res = NextResponse.redirect(new URL('/login', req.url));
res.cookies.delete('session');
return res;
}
}
export const config = {
// ✅ Statically analysable. Excludes static assets — otherwise you pay on every .js chunk.
matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg)$).*)'],
};// ❌ The mistake: treating the middleware check as the security boundary.
// app/admin/page.tsx
export default async function AdminPage() {
return ; // "middleware already checked" — no, it didn't.
}
// ✅ Re-verify at the data access layer. Middleware is a UX shortcut, not a gate.
export default async function AdminPage() {
const user = await requireUser(); // reads + verifies the session properly
if (user.role !== 'admin') notFound(); // 404, not 403 — don't leak existence
return ;
}На собеседовании подчеркните: middleware решает, куда направить запрос, но не заменяет проверку прав при доступе к данным.
Middleware — быстрый перехватчик на Edge для редиректов и заголовков; безопасность всегда дублируйте на уровне страницы и данных.
