middleware test

This commit is contained in:
2026-01-03 22:05:00 +01:00
parent c589b3c3fe
commit bc7cb2e20a
7 changed files with 680 additions and 78 deletions

View File

@@ -1,19 +1,115 @@
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { SessionGateway } from '@/lib/gateways/SessionGateway';
import { routes, routeMatchers } from '@/lib/routing/RouteConfig';
/**
* Minimal middleware that only sets x-pathname header
* All auth/role/demo logic has been removed
* Server-side route protection middleware
*
* This middleware provides comprehensive route protection by:
* 1. Setting x-pathname header for layout-level protection
* 2. Checking authentication status via SessionGateway
* 3. Redirecting unauthenticated users from protected routes
* 4. Redirecting authenticated users away from auth pages
* 5. Handling role-based access control
*/
export function middleware(request: NextRequest) {
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Set x-pathname header for layout-level protection
const response = NextResponse.next();
response.headers.set('x-pathname', pathname);
// Get session first (needed for all auth-related decisions)
const sessionGateway = new SessionGateway();
const session = await sessionGateway.getSession();
// Auth pages (login, signup, etc.) - handle before public check
if (routeMatchers.isInGroup(pathname, 'auth')) {
if (session) {
// User is authenticated, redirect away from auth page
const role = session.user?.role || 'driver';
const redirectPath = getHomePathForRole(role);
// Preserve locale if present in the original path
const localeMatch = pathname.match(/^\/([a-z]{2})\//);
if (localeMatch) {
const locale = localeMatch[1];
return NextResponse.redirect(new URL(`/${locale}${redirectPath}`, request.url));
}
return NextResponse.redirect(new URL(redirectPath, request.url));
}
// Unauthenticated users can access auth pages
return response;
}
// Public routes (no auth required, but not auth pages)
if (routeMatchers.isPublic(pathname)) {
return response;
}
// Protected routes (require authentication)
if (!session) {
// No session, redirect to login
// Preserve locale if present in the path
const localeMatch = pathname.match(/^\/([a-z]{2})\//);
const locale = localeMatch ? localeMatch[1] : null;
const redirectUrl = new URL(routes.auth.login, request.url);
redirectUrl.searchParams.set('returnTo', pathname);
// If locale is present, include it in the redirect
if (locale) {
redirectUrl.pathname = `/${locale}${redirectUrl.pathname}`;
}
return NextResponse.redirect(redirectUrl);
}
// Role-based access control
const requiredRoles = routeMatchers.requiresRole(pathname);
if (requiredRoles) {
const userRole = session.user?.role;
if (!userRole || !requiredRoles.includes(userRole)) {
// User doesn't have required role or no role at all, redirect to login
// Preserve locale if present in the path
const localeMatch = pathname.match(/^\/([a-z]{2})\//);
const locale = localeMatch ? localeMatch[1] : null;
const redirectUrl = new URL(routes.auth.login, request.url);
redirectUrl.searchParams.set('returnTo', pathname);
if (locale) {
redirectUrl.pathname = `/${locale}${redirectUrl.pathname}`;
}
return NextResponse.redirect(redirectUrl);
}
}
// All checks passed, allow access
return response;
}
/**
* Get the home path for a specific role
*/
function getHomePathForRole(role: string): string {
const roleHomeMap: Record<string, string> = {
'driver': routes.protected.dashboard,
'sponsor': routes.sponsor.dashboard,
'league-admin': routes.admin.root,
'league-steward': routes.admin.root,
'league-owner': routes.admin.root,
'system-owner': routes.admin.root,
'super-admin': routes.admin.root,
};
return roleHomeMap[role] || routes.protected.dashboard;
}
/**
* Configure which routes the middleware should run on
*/