import { NextRequest, NextResponse } from 'next/server' import { verifyToken } from '@/lib/jwt' function verifyApiKey(key: string): boolean { // API Key 以环境变量形式存储,支持多个 Key(逗号分隔) const allowedKeys = process.env.ALLOWED_API_KEYS || '' if (!allowedKeys) return false const keys = allowedKeys.split(',').map(k => k.trim()) return keys.includes(key) } export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl if (pathname.startsWith('/login') || pathname === '/') return NextResponse.next() if (pathname === '/api/auth/login') return NextResponse.next() const authHeader = request.headers.get('authorization') // API Key 认证:Bearer ak_xxx 格式 if (authHeader?.startsWith('Bearer ak_')) { const key = authHeader.slice(7) if (verifyApiKey(key)) return NextResponse.next() // 环境变量中未匹配,API 路由仍放行(route handler 可查询数据库二次验证) if (pathname.startsWith('/api/')) return NextResponse.next() } // Cookie 认证 const token = request.cookies.get('session_issue')?.value // 构建带 redirect 参数的登录 URL function buildLoginRedirect() { const loginUrl = new URL('/login', request.url) const dest = pathname + (request.nextUrl.search || '') loginUrl.searchParams.set('redirect', dest) const response = NextResponse.redirect(loginUrl) if (token) response.cookies.delete('session_issue') return response } if (pathname.startsWith('/api/')) { if (!token) return NextResponse.json({ error: '未登录' }, { status: 401 }) const valid = await verifyToken(token) if (!valid) return NextResponse.json({ error: '会话已过期' }, { status: 401 }) return NextResponse.next() } if (!token) return buildLoginRedirect() const valid = await verifyToken(token) if (!valid) return buildLoginRedirect() const response = NextResponse.next() response.headers.set('x-original-pathname', pathname + (request.nextUrl.search || '')) return response } export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'], }