56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import createIntlMiddleware from 'next-intl/middleware';
|
|
import { routing } from './i18n/routing';
|
|
import type { NextRequest } from 'next/server';
|
|
import { NextResponse } from 'next/server';
|
|
import { getToken } from 'next-auth/jwt';
|
|
|
|
const protectedRoutes: Record<string, string[]> = {
|
|
'/example': ['ad'],
|
|
};
|
|
|
|
const intlMiddleware = createIntlMiddleware(routing);
|
|
|
|
export default async function middleware(req: NextRequest) {
|
|
const pathname = req.nextUrl.pathname;
|
|
const segments = pathname.split('/');
|
|
const locale = segments[1];
|
|
const pathWithoutLocale = '/' + segments.slice(2).join('/');
|
|
|
|
const matchedRoute = Object.keys(protectedRoutes).find((route) => {
|
|
return (
|
|
pathWithoutLocale === route || pathWithoutLocale.startsWith(route + '/')
|
|
);
|
|
});
|
|
|
|
// Short-circuit: skip token fetch entirely for public routes
|
|
if (!matchedRoute) {
|
|
return intlMiddleware(req);
|
|
}
|
|
|
|
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
|
|
|
|
if (!token) {
|
|
const url = req.nextUrl.clone();
|
|
url.pathname = '/api/auth/signin';
|
|
url.searchParams.set('callbackUrl', pathname);
|
|
return NextResponse.redirect(url);
|
|
}
|
|
|
|
const requiredRoles = protectedRoutes[matchedRoute];
|
|
if (requiredRoles.length > 0) {
|
|
const userRoles = token.roles ?? [];
|
|
const hasRole = requiredRoles.some((role) => userRoles.includes(role));
|
|
if (!hasRole) {
|
|
const url = req.nextUrl.clone();
|
|
url.pathname = `/${locale}/403`;
|
|
return NextResponse.redirect(url);
|
|
}
|
|
}
|
|
|
|
return intlMiddleware(req);
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ['/((?!api|trpc|_next|_vercel|.*\\..*).*)'],
|
|
};
|