JWT令牌认证失败:登录后无法访问权限控制的About页面
JWT认证失败排查:登录后无法访问About页面
问题描述
我开发了登录页面与About页面,仅允许已登录用户访问About页面。尝试使用登录时生成的JWT令牌进行用户认证,但输入正确凭据登录后,令牌仍无法通过认证,不清楚问题所在。
相关代码
登录与令牌生成代码
const express = require("express"); const { default: mongoose } = require("mongoose"); const router = express.Router(); const bcrypt = require("bcrypt"); const jwt = require("jsonwebtoken"); require("../db/conn"); const User = require("../model/userSchema"); const cookieParser = require('cookie-parser'); const Authenticate = require("../middleware/authenticate"); router.use(cookieParser()); // Login route router.post("/signin", async (req, res) => { if (!req.body.email || !req.body.password) { return res.status(400).json({ error: "请填写必填字段" }); } try { const foundUser = await User.findOne({ email: req.body.email }); if (!foundUser) { return res.status(400).json({ message: "用户不存在" }); } const isPasswordMatch = await bcrypt.compare(req.body.password, foundUser.password); if (!isPasswordMatch) { return res.json({ message: "密码错误" }); } // 生成JWT令牌 const token = jwt.sign( { user_id: foundUser._id, email: req.body.email }, process.env.TOKEN_KEY, { expiresIn: "720h" } ); // 将令牌添加到用户的tokens数组并保存 foundUser.tokens = foundUser.tokens.concat({ token }); await foundUser.save(); // 将令牌设置到Cookie中 res.cookie("jwtoken", token, { expires: new Date(Date.now() + 720 * 60 * 60 * 1000), httpOnly: true, // 防止前端JS读取,提升安全性 sameSite: "Strict" // 根据跨域需求可调整为Lax或None }); res.json({ message: "登录成功" }); } catch (err) { console.log(err); res.status(500).json({ error: "服务器内部错误" }); } }); // About页面路由 router.get("/about", Authenticate, (req, res) => { console.log("about路由运行"); res.send(req.rootUser); }); module.exports = router;
用户认证中间件代码
require("dotenv").config({ path: "./config.env" }); const jwt = require("jsonwebtoken"); const User = require("../model/userSchema"); const Authenticate = async (req, res, next) => { try { const token = req.cookies.jwtoken; if (!token) { throw new Error("未提供令牌"); } const verifyToken = jwt.verify(token, process.env.TOKEN_KEY); // 匹配JWT payload中存储的user_id字段 const rootUser = await User.findOne({ _id: verifyToken.user_id, "tokens.token": token }); if (!rootUser) { throw new Error("用户未找到"); } req.token = token; req.rootUser = rootUser; req.userID = rootUser._id; next(); } catch (err) { console.log(err); res.status(401).send("未授权:" + err.message); } }; module.exports = Authenticate;
React端About页面权限控制代码
const navigate = useNavigate(); const callAboutPage = async () => { try { const res = await fetch("/about", { method: "GET", headers: { Accept: "application/json", "Content-Type": "application/json" }, credentials: "include" }); const data = await res.json(); console.log(data); // 修复状态判断逻辑 if (res.status !== 200) { const error = new Error(data.error || "请求失败"); throw error; } } catch (err) { console.log(err); navigate("/login"); } };
问题根源与修复说明
- 登录路由回调逻辑错误:原代码在
bcrypt.compare的回调中直接return res,导致令牌生成、用户文档保存、Cookie设置等后续代码完全未执行。改用async/await重构后,确保登录验证成功后才执行令牌相关逻辑。 - 未向前端设置Cookie:原代码生成令牌后未通过
res.cookie将令牌发送给前端,导致前端请求时Cookie中无jwtoken,中间件无法获取令牌。 - JWT payload字段不匹配:中间件原用
verifyToken._id查询用户,但JWT payload中存储的是user_id,导致查询不到用户,改为verifyToken.user_id即可匹配。 - React端状态判断逻辑错误:原代码
!res.status === 200逻辑错误(!优先级高于===),改为res.status !== 200才能正确判断非200状态。
内容的提问来源于stack exchange,提问作者Jatin
相关产品推荐
相关产品推荐

