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

Node.js如何实现仅管理员可提交数据写入数据库的权限控制

问题根因
  • 接口内的用户查询逻辑完全错误:await User.find({ admin: true })是查询全表所有管理员账号,只要系统中存在任意一个管理员账号,该查询就会返回结果,和当前发起请求的登录用户没有任何关系,等于完全没做权限判断。
  • 布尔判断逻辑错误:User.find()返回值永远是数组,哪怕查询无匹配结果也会返回空数组[],而JS中空数组的布尔值为true,因此if (user)判断永远成立,所有请求都会被放行。
  • 身份认证中间件存在隐性bug:代码中throw new error()的构造函数首字母未大写,JS内置错误构造函数为Error,小写写法会触发引用错误。
正确实现方案

你的身份认证中间件已经将当前登录用户挂载到了req.user属性上,不需要在业务接口中重复查询用户,直接基于该对象做权限判断即可,推荐将管理员权限校验抽为独立可复用的中间件,避免重复代码。

1. 新增管理员权限校验中间件

const requireAdmin = (req, res, next) => {
  // 直接取auth中间件挂载的当前登录用户判断权限
  if (!req.user?.admin) {
    // 无操作权限返回403状态码,符合HTTP语义:401代表未认证,403代表已认证但无权限
    return res.status(403).send("You are not allowed to perform this action");
  }
  next();
};

2. 修正身份认证中间件的bug

const authentication = async (req, res, next) => {
  try {
    const token = req.header("Authorization").replace("Bearer ", "");
    const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY);
    const user = await User.findOne({ _id: decoded._id, "tokens.token": token });

    if (!user) {
      throw new Error(); // 修正首字母大写问题
    }

    req.token = token
    req.user = user
    next();
  } catch (e) {
    res.status(401).send("Authentication failed");
  }
};

3. 修正业务接口逻辑

// 中间件按顺序执行:先校验登录身份,再校验管理员权限
router.post("/bus/add", auth, requireAdmin, async (req, res) => {
  try {
    const bus = new Bus(req.body);
    await bus.save();
    res.status(201).send(bus);
  } catch (e) {
    res.status(500).json({
      message: "Please enter the valid data",
    });
  }
});
注意事项
  • 所有权限校验必须绑定当前登录上下文的用户身份,禁止使用无用户维度筛选的全局查询做权限判断,这类写法等于完全不设防。
  • 查询单个用户时优先使用findOne(),避免find()返回数组带来的空值判断坑点。
  • 权限校验逻辑尽量抽为公共中间件,避免每个业务接口重复编写,减少漏加校验、逻辑写错的概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 02:48:32