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

Express权限验证中间件返回‘未授权’错误原因排查求助

权限中间件中ObjectId与字符串比较失败的原因及解决

我开发了一个权限保护中间件protect,通过JWT解析获取decoded.id并赋值给req.userId,同时查询数据库获取排除password字段的req.user。在verifyandAuth中间件中,控制台显示req.user._id与req.params.id完全相同,但直接用===比较会返回‘Not authorised’(未授权)错误;若将req.user._id替换为decoded.id进行比较,则中间件可正常通过,请问这一现象的原因是什么?

Protect 中间件代码

export const protect = async (req, res, next) => {
  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith("Bearer")
  )
    try {
      {
        token = req.headers.authorization.split(" ")[1];
        const decoded = jwt.verify(token, "kris");
        req.userId = decoded.id;
        req.user = await User.findById(decoded.id).select("-password");
        next();
      }
    } catch (error) {
      res.status(400).json(error.message);
    }

  if (!token) {
    return res.status(400).json("Invalid Token");
  }
};

VerifyandAuth 中间件代码

export const verifyandAuth = (req, res, next) => {
  protect(req, res, () => {
    console.log(req.user._id, req.params.id);

    if (req.user._id === req.params.id || req.isAdmin) {
      next();
    } else {
      res.status(400).json("Not authorised");
    }
  });
};

问题原因

  • req.user._id是MongoDB返回的ObjectId对象,而req.params.id是从URL中提取的字符串类型。===属于严格相等比较,要求值和类型都完全一致,所以对象和字符串直接对比会返回false。
  • 控制台显示两者“相同”是因为控制台在打印时会自动将ObjectId对象转换为字符串形式展示,但实际内存中的数据类型并不一致。
  • decoded.id是从JWT payload中解析出的字符串(JWT存储的ID默认是字符串格式),和req.params.id类型一致,因此用===对比可以匹配成功。

解决方法

推荐以下几种可行的处理方式:

  • 将ObjectId转为字符串后对比:req.user._id.toString() === req.params.id
  • 使用MongoDB ObjectId自带的equals方法:req.user._id.equals(req.params.id),该方法会自动处理类型差异,直接对比ID的实际值
  • (可选)在JWT编码时存储ObjectId的字符串形式,确保解析后和URL参数类型统一(不过这一步不是必须的,前两种方法更直接)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:09:25