Next.js 13 App Router如何配置API仅允许前端请求访问?
阻止外部请求访问Next.js 13 App目录下的API接口
问题分析
你当前的Middleware判断逻辑request.nextUrl.pathname.startsWith('/api')完全失效——不管是外部curl请求还是前端内部发起的请求,目标路径都是/api/get-token,所以都会返回true。要区分内部和外部请求,需要依赖请求头这类无法轻易伪造(或伪造成本高)的标识。
可行解决方案
方法1:检查Origin/Referer请求头
前端内部发起的请求会自动带上同域的Origin或Referer头,而外部直接请求(比如curl)默认不会携带这些头,或者携带的是其他域的值。
修改后的Middleware代码:
import { NextRequest, NextResponse } from 'next/server'; enum MiddlewareRoutes { GET_TOKEN = '/api/get-token', } const middlewareHandler = async ( route: MiddlewareRoutes, request: NextRequest, response: NextResponse ): Promise<NextResponse> => { switch (route) { case MiddlewareRoutes.GET_TOKEN: { // 判断是否为内部前端请求 const origin = request.headers.get('origin'); const referer = request.headers.get('referer'); const isLocalOrigin = origin === 'http://localhost:3000'; // 生产环境替换为你的域名 const isLocalReferer = referer?.startsWith('http://localhost:3000/'); const fromFE = isLocalOrigin || isLocalReferer; console.log('From Frontend = ', fromFE); // 如果不是内部请求,直接拦截 if (!fromFE) { return new NextResponse('Unauthorized', { status: 401 }); } return response; } default: { return response; } } }; export async function middleware(request: NextRequest) { const response = NextResponse.next(); const pathname = request.nextUrl.pathname as MiddlewareRoutes; // 只处理目标路由,避免不必要的逻辑 if (Object.values(MiddlewareRoutes).includes(pathname)) { return await middlewareHandler(pathname, request, response); } return response; } export const config = { matcher: ['/api/:path*'], };
方法2:使用Next.js内部请求标识(更可靠)
当客户端组件通过fetch或自定义cacheFetch发起请求时,Next.js会自动添加x-nextjs-data请求头(仅内部请求携带),可以通过检查这个头来判断:
// 替换middlewareHandler里的fromFE判断逻辑 const fromFE = request.headers.get('x-nextjs-data') !== null; console.log('From Frontend = ', fromFE); if (!fromFE) { return new NextResponse('Unauthorized', { status: 401 }); }
验证效果
- 用
curl http://localhost:3000/api/get-token请求时,日志输出From Frontend = false,且返回401未授权 - 前端组件通过
useEffect发起请求时,日志输出From Frontend = true,正常返回接口数据
内容的提问来源于stack exchange,提问作者Shivam Sahil
相关产品推荐
相关产品推荐

