NextJS中JWT路由保护失效问题求助
NextJS JWT验证中间件失效:POST请求可绕过验证插入数据
我正在开发一个NextJS项目,使用JWT保护部分路由,但JWT验证中间件失效——index.js中的POST请求可绕过验证向数据库插入数据。已确认验证中间件已触发,但请求数据仍被插入数据库。
问题代码
verifyAuthToken.middleware.js
import jwt from "jsonwebtoken"; export default function verifyAuthToken(req, res) { try { const token = req.headers; if (!token) { return res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); } const { userId } = jwt.verify( req.headers.authorization, process.env.TOKEN_SECRET ); if (!userId) { return res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); } req.userId = userId; } catch (error) { res.status(401).json({ success: false, msg: "You are not authorized to access this route", error: error.message, }); } }
index.js(API路由)
import verifyAuthToken from "../../../middleware/verifyAuthToken.middleware"; import Evoluter from "../../../models/Evoluter.model"; import dbConnect from "../../../server-utils/connectDB"; import { sendEmail } from "../../../server-utils/sendEmail"; import baseURL from "../../../utils/baseURL"; export default async (req, res) => { const { method } = req; verifyAuthToken(req, res); await dbConnect(); switch (method) { // @route GET api/evoluters // @desc Create new evoluter // @access Private case "POST": try { const { name, email } = req.body; const evoluter = await Evoluter.findOne({ email: email.toLowerCase() }); if (evoluter) { return res.status(400).json({ success: false, msg: "Evoluter already exists", }); } const newEvoluter = await Evoluter.create({ name, email: email.toLowerCase(), }); try { await sendEmail({ email: newEvoluter.email, subject: "Welcome to Rubrica", message: `Hi ${newEvoluter.name}, welcome to Rubrica. Please click on the link below to activate your account. ${baseURL}/home/${newEvoluter._id}`, }); res.status(201).json({ success: true, data: newEvoluter, msg: "Evoluter created successfully. Please check your email to activate your account.", }); } catch (error) { console.log(error); res.status(500).json({ success: false, msg: "Error sending invitation email, please let the admin know.", }); } } catch (error) { res.status(400).json({ success: false, msg: "Sorry, we couldn't send the invitation. Please try again.", error: error, }); } break; default: res.status(400).json({ success: false, msg: "Invalid request", }); break; } };
问题原因
Token获取逻辑错误:中间件中把
req.headers赋值给token,然后判断!token——req.headers永远存在,这个判断完全无效。正确的做法应该检查req.headers.authorization是否存在,并且处理Bearer <token>的格式。未终止后续代码执行:即使中间件返回了401响应,API路由中的
await dbConnect()和POST请求逻辑依然会执行。中间件的return res.status(401)...只是结束中间件函数本身,不会阻止API路由里的后续代码运行。
修复方案
方案1:使用NextJS中间件的next()模式
修正后的verifyAuthToken.middleware.js
import jwt from "jsonwebtoken"; // 添加next参数,验证通过后调用next()放行 export default function verifyAuthToken(req, res, next) { try { const authHeader = req.headers.authorization; // 检查Authorization头是否存在,且符合Bearer格式 if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); } // 提取token部分 const token = authHeader.split(' ')[1]; const { userId } = jwt.verify(token, process.env.TOKEN_SECRET); if (!userId) { return res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); } req.userId = userId; // 验证通过,执行后续代码 next(); } catch (error) { res.status(401).json({ success: false, msg: "You are not authorized to access this route", error: error.message, }); } }
修正后的index.js
import verifyAuthToken from "../../../middleware/verifyAuthToken.middleware"; import Evoluter from "../../../models/Evoluter.model"; import dbConnect from "../../../server-utils/connectDB"; import { sendEmail } from "../../../server-utils/sendEmail"; import baseURL from "../../../utils/baseURL"; export default async (req, res) => { const { method } = req; // 用Promise包装中间件,确保验证不通过时终止后续代码 await new Promise((resolve) => { verifyAuthToken(req, res, resolve); }); // 检查是否已发送响应,避免重复执行逻辑 if (res.headersSent) { return; } await dbConnect(); switch (method) { case "POST": try { const { name, email } = req.body; const evoluter = await Evoluter.findOne({ email: email.toLowerCase() }); if (evoluter) { return res.status(400).json({ success: false, msg: "Evoluter already exists", }); } const newEvoluter = await Evoluter.create({ name, email: email.toLowerCase(), }); try { await sendEmail({ email: newEvoluter.email, subject: "Welcome to Rubrica", message: `Hi ${newEvoluter.name}, welcome to Rubrica. Please click on the link below to activate your account. ${baseURL}/home/${newEvoluter._id}`, }); res.status(201).json({ success: true, data: newEvoluter, msg: "Evoluter created successfully. Please check your email to activate your account.", }); } catch (error) { console.log(error); res.status(500).json({ success: false, msg: "Error sending invitation email, please let the admin know.", }); } } catch (error) { res.status(400).json({ success: false, msg: "Sorry, we couldn't send the invitation. Please try again.", error: error, }); } break; default: res.status(400).json({ success: false, msg: "Invalid request", }); break; } };
方案2:用Promise包装中间件(更简洁)
修正后的verifyAuthToken.middleware.js
import jwt from "jsonwebtoken"; // 返回Promise,方便API路由中await处理 export default function verifyAuthToken(req, res) { return new Promise((resolve, reject) => { try { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); return reject(new Error("Authorization header missing or invalid")); } const token = authHeader.split(' ')[1]; const { userId } = jwt.verify(token, process.env.TOKEN_SECRET); if (!userId) { res.status(401).json({ success: false, msg: "You are not authorized to access this route", }); return reject(new Error("Invalid user ID in token")); } req.userId = userId; resolve(); } catch (error) { res.status(401).json({ success: false, msg: "You are not authorized to access this route", error: error.message, }); reject(error); } }); }
修正后的index.js
import verifyAuthToken from "../../../middleware/verifyAuthToken.middleware"; import Evoluter from "../../../models/Evoluter.model"; import dbConnect from "../../../server-utils/connectDB"; import { sendEmail } from "../../../server-utils/sendEmail"; import baseURL from "../../../utils/baseURL"; export default async (req, res) => { const { method } = req; try { // 等待验证完成,验证失败会进入catch await verifyAuthToken(req, res); } catch (error) { // 验证失败,已返回响应,直接终止 return; } // 双重检查避免重复执行 if (res.headersSent) return; await dbConnect(); switch (method) { case "POST": try { const { name, email } = req.body; const evoluter = await Evoluter.findOne({ email: email.toLowerCase() }); if (evoluter) { return res.status(400).json({ success: false, msg: "Evoluter already exists", }); } const newEvoluter = await Evoluter.create({ name, email: email.toLowerCase(), }); try { await sendEmail({ email: newEvoluter.email, subject: "Welcome to Rubrica", message: `Hi ${newEvoluter.name}, welcome to Rubrica. Please click on the link below to activate your account. ${baseURL}/home/${newEvoluter._id}`, }); res.status(201).json({ success: true, data: newEvoluter, msg: "Evoluter created successfully. Please check your email to activate your account.", }); } catch (error) { console.log(error); res.status(500).json({ success: false, msg: "Error sending invitation email, please let the admin know.", }); } } catch (error) { res.status(400).json({ success: false, msg: "Sorry, we couldn't send the invitation. Please try again.", error: error, }); } break; default: res.status(400).json({ success: false, msg: "Invalid request", }); break; } };
关键修复点总结
- 修正Token提取逻辑:正确处理
Authorization: Bearer <token>的格式 - 控制代码流:确保验证失败时,后续的数据库操作和业务逻辑不会执行
- 增加格式校验:防止无意义的token格式绕过验证
内容的提问来源于stack exchange,提问作者Manikangkan
相关产品推荐
相关产品推荐

