You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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参数匹配的方式,需排查以下两点:

  1. 参数传递问题:确保前端请求时拼接了?id=xxx参数,值与Cookie中的uid/guestId一致
  2. 路由匹配问题:如果你的路由是动态路由(如/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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:17:39