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

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");
  }
};

问题根源与修复说明

  1. 登录路由回调逻辑错误:原代码在bcrypt.compare的回调中直接return res,导致令牌生成、用户文档保存、Cookie设置等后续代码完全未执行。改用async/await重构后,确保登录验证成功后才执行令牌相关逻辑。
  2. 未向前端设置Cookie:原代码生成令牌后未通过res.cookie将令牌发送给前端,导致前端请求时Cookie中无jwtoken,中间件无法获取令牌。
  3. JWT payload字段不匹配:中间件原用verifyToken._id查询用户,但JWT payload中存储的是user_id,导致查询不到用户,改为verifyToken.user_id即可匹配。
  4. React端状态判断逻辑错误:原代码!res.status === 200逻辑错误(!优先级高于===),改为res.status !== 200才能正确判断非200状态。

内容的提问来源于stack exchange,提问作者Jatin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:45:47