如何在Next.js中保护API路由,同时允许访客用户写入数据库?
解决方案:拦截直接访问特定GET接口
要阻止用户直接通过URL或Postman访问http://www.website.com/api/route/random-type的GET请求,你可以从请求来源验证或CSRF Token校验入手,同时解决原代码中req.query.id为undefined的问题。
方案一:通过Referer请求头拦截(简单快速)
直接访问或Postman发起的请求通常不会携带合法的Referer头(或头信息不来自你的网站),可以通过这个特性拦截:
export default async function handler(req, res) { const { method } = req; // 仅针对GET请求做拦截 if (method === 'GET') { const allowedDomain = 'http://www.website.com'; const referer = req.headers.referer; // 验证Referer是否来自本站,无Referer直接拦截 if (!referer || !referer.startsWith(allowedDomain)) { return res.status(403).json({ message: '禁止直接访问该接口' }); } } // 后续业务逻辑:处理访客用户写入数据库 const userCookieId = req.cookies?.uid || req.cookies?.guestId; // ... 你的数据库操作代码 res.status(200).json({ success: true }); }
方案二:CSRF Token校验(更安全可靠)
如果需要更严格的验证,推荐使用CSRF Token机制,确保请求来自你的前端页面:
1. 前端页面准备Token
页面加载时从Cookie获取后端生成的CSRF Token,请求时携带在请求头:
// 从Cookie中提取Token const getCsrfToken = () => { return document.cookie.split('; ') .find(row => row.startsWith('csrfToken=')) ?.split('=')[1] || ''; }; // 发起请求时携带Token fetch('http://www.website.com/api/route/random-type', { method: 'GET', headers: { 'X-CSRF-Token': getCsrfToken() }, credentials: 'include' // 确保携带Cookie });
2. 后端生成并验证Token
首先在用户访问页面时生成CSRF Token并写入Cookie,然后在接口中验证:
// 生成随机CSRF Token工具函数 const generateCsrfToken = () => { return Math.random().toString(36).slice(2, 18) + Math.random().toString(36).slice(2, 18); }; // 页面路由的handler(示例:Next.js的页面路由) export async function getServerSideProps({ res }) { const csrfToken = generateCsrfToken(); // 设置Cookie,允许前端读取(HttpOnly设为false) res.setHeader('Set-Cookie', `csrfToken=${csrfToken}; Path=/; SameSite=Strict; HttpOnly=false`); return { props: {} }; } // 目标接口的handler export default async function handler(req, res) { const { method } = req; if (method === 'GET') { const tokenFromCookie = req.cookies?.csrfToken; const tokenFromHeader = req.headers['x-csrf-token']; // 验证Token是否存在且匹配 if (!tokenFromCookie || !tokenFromHeader || tokenFromCookie !== tokenFromHeader) { return res.status(403).json({ message: '非法请求' }); } } // 业务逻辑:处理访客用户数据 const userCookieId = req.cookies?.uid || req.cookies?.guestId; // ... 数据库操作 res.status(200).json({ success: true }); }
解决原代码中req.query.id为undefined的问题
如果坚持使用Cookie与URL参数匹配的方式,需排查以下两点:
- 参数传递问题:确保前端请求时拼接了
?id=xxx参数,值与Cookie中的uid/guestId一致 - 路由匹配问题:如果你的路由是动态路由(如
/api/route/random-type/[id]),需用req.params.id替代req.query.id获取参数:
const userId = req.params.id; // 动态路由参数用params获取 const userCookieId = req.cookies?.uid || req.cookies?.guestId; const authUser = userId === userCookieId; if (!authUser) { return res.status(403).json({ message: '请求非法' }); }
内容的提问来源于stack exchange,提问作者Omilight
相关产品推荐
相关产品推荐

