【问题标题】:Mongoose check if user owns document before updating猫鼬在更新之前检查用户是否拥有文档
【发布时间】:2019-08-18 05:27:26
【问题描述】:

我正在尝试检查 用户 在更新文档之前是否拥有该文档删除它,并希望尽可能保持此文档干燥。理想情况下,我不必必须对数据库进行两次调用,而我首先要在findById().then(doc => {check if user owns document and then -> doc.findByIdAndUpdate() }) 处调用数据库,而是将其保留为对数据库的一次调用。

我经常不得不对 express routes 执行此检查,并考虑在 mongoose .pre('update') 中间件上实现这一层逻辑。但我不知道如何将传入的 useridreq 对象 传递给我的中间件验证功能?

有没有更好的层来实现这个检查功能?还是每次我想检查用户是否拥有文档并在每个快速路由中写出时,我都必须向数据库发出两个请求?

我目前的实现是:

const addDocToDoc = (req, res, next) => {
    let doc1id = req.params.id;
    let doc2id  = req.params.doc2id;
    Doc1.findById(doc1id)
        .then(doc1 => {
            if(userCanAlter(doc1, req.user, res)) {
                doc1.doc2s.push(doc2id)
                return doc1.save().then(updatedDoc1 => res.send(updatedDoc1))
            }
        }).catch(next)
}

userCanAlter() 看起来像这样:

function userCanAlter(instance, user, res) {
        if (!instance) { res.status(404).send("Document does not exist."); return false}
        if (instance.user != user) { res.status(401).send("User unauthorized"); return false}
        else return true;
    }

显然,这是一个非常简单的更新,但更复杂的更新需要在保存之前进行更多配置。

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    发现当前的实施是最好的和最干燥的实施。

    【讨论】:

      【解决方案2】:

      您可以简单地将您的用户包装在 find 查询中并使用 findOne(),类似于:

      const addDocToDoc = (req, res, next) => {
          const {
              user = ''
          } = req;
          const {
              id = '', doc2id = ''
          } = req.params;
          Doc1.findOne({
                  _id: id,
                  user
              })
              .then(doc => {
                  if (!doc) {
                      return res.status(400).json({
                          message: 'User Not Found!!'
                      });
                  }
                  doc.doc2s.push(doc2id);
                  doc.save()
                      .then(updatedDoc1 => res.status(200).json(updatedDoc1))
                      .catch(err => res.status(500).json({
                          message: 'Error While Updating!!',
                          error: err
                      }));
              })
              .catch(err => res.status(500).json({
                  message: 'Error While Fetching!!',
                  error: err
              }));
      }
      

      另外我建议你在命名方面做一些工作,因为这可能会搞砸几次。

      如果您想为未经授权的用户抛出特定错误,您可以坚持自己的实施方式,只是不需要单独的方法来检查所有权。我用 async/await 简化了它,代码是:

      const addDocToDoc = async (req, res, next) => {
          try {
              const {
                  user = ''
              } = req;
              const {
                  id = '', doc2id = ''
              } = req.params;
              const doc = await Doc1.findById(id);
              if (!doc || !doc.user || doc.user !== user) {
                  return res.status(401).json({
                      message: 'Unauthorized User!!'
                  });
              }
              doc.doc2s.push(doc2id);
              const updatedDoc1 = await doc.save();
              return res.status(200).json(updatedDoc1);
          } catch (err) {
              res.status(500).json({
                  message: 'Error While Updating Record!!',
                  error: err
              });
          }
      }
      

      Ps:你可能需要一些修改,因为我没有机会运行它。

      希望这会有所帮助:)

      【讨论】:

      • 虽然这会处理在数据库中搜索文档并仅在用户是所有者时返回一个,但这不会暴露以下两种错误情况:1)找不到文档 - 404(与您的答案一起处理m) 2) 找到文档但用户未经授权 - 401
      • 这也执行与当前解决方案相同数量的对我的数据库的调用,代码为 2 倍。所以这不是一个干燥的答案。我希望有一个中间件层,我能够在每次更新之前通过并检查用户 ID。还是谢谢!
      • 嗯,我们已经在 mongoose 中提供了 pre save() 中间件,但是如果您特别需要抛出未经授权的错误,那么这也行不通。在这种情况下,你正在做的方式是最好的方式。虽然它需要一些修改,但我在答案中添加了简化代码
      • 虽然我很欣赏您的响应,但您的附加代码错误地处理了错误,因为找不到文档需要 404 服务器响应。这不满足给定的问题,并建议删除这两个答案作为可能的答案。
      • 我不明白你到底想说什么,但是如果你需要在没有记录的情况下抛出单独的错误,你可以简单地拆分条件:)
      猜你喜欢
      • 2016-05-24
      • 2019-05-31
      • 2021-12-31
      • 2017-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      相关资源
      最近更新 更多