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

更新用户接口报错Cannot read properties of undefined (reading 'id')

问题报错说明

开发用户信息更新接口时,请求PUT /:id接口触发报错:Cannot read properties of undefined (reading 'id'),请求始终无法通过verifyTokenAndAuthorization中间件校验。
控制台日志顺序:

  • 首先打印日志req recived for login
  • 随后抛出上述错误,报错定位在verifyToken.js第20行,未打印req went past verification日志

涉及的问题代码:
用户更新接口:

router.put("/:id", verifyTokenAndAuthorization, async (req, res) => {
  if (req.user.password) {
    req.body.password = CryptoJS.AES.encrypt(
      req.body.password,
      process.env.PASS_SEC
    ).toString();
  }
  try {
    const updatedUser = await User.findByIdAndUpdate(
      req.user.id,
      {
        $set: req.body,
      },
      { new: true }
    );
    res.status(200).json(updatedUser);
  } catch (err) {
    res.status(500).json(err);
  }
});

权限校验中间件:

const verifyTokenAndAuthorization = (req, res, next) => {
  verifyToken(req, res, () => {
    console.log("req recived for login");
    if (req.user.id === req.params.id || req.user.isAdmin) {
      console.log("req went past verification");
      next();
    } else {
      res.status(403).json("You are not allowed to access!");
    }
  });
};
根因定位

报错触发点是权限校验中间件里的req.user.id读取逻辑:执行到这行时req.user的值为undefined,读取undefined的id属性直接抛错。
结合执行链路可确定核心问题出在前置的verifyToken中间件:

  • verifyToken在token解析失败、请求未携带合法token的场景下,没有提前返回401错误,仍然调用了传入的回调函数,导致逻辑走到了id判断的分支
  • verifyToken没有在JWT解析成功后,将解析出的用户信息正确挂载到req.user属性上,导致回调中访问不到req.user

另外现有代码还存在两个隐藏逻辑bug:

  • 更新接口中判断是否需要加密密码的条件写为req.user.password,req.user是JWT解析出的信息,不会存储用户明文密码,该判断永远不会生效,用户提交的新密码不会被加密
  • 更新用户时查询条件写为req.user.id,和路由定义的/:id参数、权限校验逻辑不匹配,管理员更新其他用户信息时会错误修改当前登录账号的信息
修复方案

1. 修复verifyToken中间件逻辑

确保verifyToken仅在JWT解析成功、正确挂载req.user后才调用next()执行后续逻辑,异常场景提前返回错误,参考实现:

const jwt = require('jsonwebtoken');
const verifyToken = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    return res.status(401).json("未携带认证凭证");
  }
  const token = authHeader.split(" ")[1];
  jwt.verify(token, process.env.JWT_SEC, (err, payload) => {
    if (err) {
      return res.status(401).json("token无效或已过期");
    }
    // 解析成功后将用户信息挂载到req.user
    req.user = payload;
    next();
  })
}

2. 修复用户更新接口逻辑

调整密码加密判断条件、用户更新查询条件,和权限逻辑对齐:

router.put("/:id", verifyTokenAndAuthorization, async (req, res) => {
  // 加密用户提交的新密码,不是req.user上的密码
  if (req.body.password) {
    req.body.password = CryptoJS.AES.encrypt(
      req.body.password,
      process.env.PASS_SEC
    ).toString();
  }
  try {
    // 用路由参数中的id作为更新查询条件,匹配权限校验逻辑
    const updatedUser = await User.findByIdAndUpdate(
      req.params.id,
      {
        $set: req.body,
      },
      { new: true }
    );
    res.status(200).json(updatedUser);
  } catch (err) {
    res.status(500).json(err);
  }
});

3. 校验请求格式

前端发起请求时,需要在请求头中正确携带token,格式为:
Authorization: Bearer <登录接口返回的有效token>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:36:22