在Mongodb中创建Express route后,如何修改它以登录用户?

在Mongodb中创建Express route后,如何修改它以登录用户?,mongodb,express,Mongodb,Express,我有下面的路线。如果我在MongoDB中手动添加文档,它就会工作。但是,我想处理这样一种情况:找不到用户,创建用户,然后自动登录 修改此路线的最佳方式是什么 router.post("/loginViaFacebook", (req, res) => { const userEmail = req.body.email; const errors = {}; User.findOne({ email: userEmail }).then(user => { if

我有下面的路线。如果我在MongoDB中手动添加文档,它就会工作。但是,我想处理这样一种情况:找不到用户,创建用户,然后自动登录

修改此路线的最佳方式是什么

router.post("/loginViaFacebook", (req, res) => {
  const userEmail = req.body.email;
  const errors = {};

  User.findOne({ email: userEmail }).then(user => {
    if (!user) {
      new User({
        facebookId: req.body.facebookId,
        name: req.body.name,
        email: req.body.email,
        pictureUrl: req.body.picture
      }).save();
    } else {
      const payload = {
        facebookId: user.id,
        name: user.name,
        email: user.email,
        pictureUrl: user.picture
      };

      jwt.sign(payload, secretOrKey, { expiresIn: 3600 }, (err, token) => {
        res.json({ success: true, token: "Bearer " + token });
      });

      console.log("success!");
    }
  });
});

将新用户对象保存到数据库后,可以从返回的结果中获取id。我不太了解mongo,因此您必须查看从
.save()
返回的结果,然后从中提取id。以下是总体结构:

const promisify = require('util').promisify;
const jwt.signPromise = promisify(jwt.sign);

/**
 * @route POST api/auth/loginViaFacebook
 * @desc Login User via Facebook/
 * @access public
 */
router.post("/loginViaFacebook", async (req, res) => {
    const userEmail = req.body.email;
    const errors = {};

    try {
        let user = await User.findOne({
            email: userEmail
        });
        if (!user) {
            user = new User({
                facebookId: req.body.facebookId,
                name: req.body.name,
                email: req.body.email,
                pictureUrl: req.body.picture
            });
            user = await user.save();
        }
        const payload = {
            facebookId: user.facebookId,
            name: user.name,
            email: user.email,
            pictureUrl: user.picture
        };

        let token = await jwt.signPromise(payload, secretOrKey, {expiresIn: 3600});
        res.json({success: true, token: "Bearer " + token});

    } catch (e) {
        // send some sort of error response here
        console.log(e);
        res.sendStatus(500);
    }
});
如果您不想使用
wait
,而想保持原来的结构,只需将复制的代码移动到一个公共函数中即可

/**
 * @route POST api/auth/loginViaFacebook
 * @desc Login User via Facebook/
 * @access public
 */
router.post("/loginViaFacebook", (req, res) => {
  const userEmail = req.body.email;
  const facebookId = req.body.facebookId;

  function finish(user) {
    const payload = {
      facebookId: user.facebookId,
      name: user.name,
      email: user.email,
      pictureUrl: user.picture
    };

    jwt.sign(payload, secretOrKey, { expiresIn: 3600 }, (err, token) => {
      if (err) {
          console.log(err);
          res.sendStatus(500);
          return;
      }
      res.json({ success: true, token: "Bearer " + token });
    });
    return;
  }

  // Find user by email. ( Down below { email } in ES6 is same as { email: email }
  User.findOne({ email: userEmail }).then(user => {
    if (!user) {
      new User({
        facebookId: facebookId,
        name: req.body.name,
        email: userEmail,
        pictureUrl: req.body.picture
      }).save(function(err, user) {
        if (err) {
            res.send({ errors: err });
            return;
        }
        finish(user);        
      });
    } else {
      finish(user);
    }
  }).catch(err => {
      console.log(err);
      res.sendStatus(500);
  });
});

我最终修改了代码,如下所示:

/**
 * @route POST api/auth/loginViaFacebook
 * @desc Login User via Facebook/
 * @access public
 */
router.post("/loginViaFacebook", (req, res) => {
  const userEmail = req.body.email;
  const facebookId = req.body.facebookId;

  // Find user by email. ( Down below { email } in ES6 is same as { email: email }
  User.findOne({ email: userEmail }).then(user => {
    if (!user) {
      new User({
        facebookId: facebookId,
        name: req.body.name,
        email: userEmail,
        pictureUrl: req.body.picture
      }).save(function(err, user) {
        if (err) res.send({ errors: err });

        const payload = {
          facebookId: user.facebookId,
          name: user.name,
          email: user.email,
          pictureUrl: user.picture
        };

        jwt.sign(payload, secretOrKey, { expiresIn: 3600 }, (err, token) => {
          res.json({ success: true, token: "Bearer " + token });
        });
        return;
      });
    }

    const payload = {
      facebookId: user.facebookId,
      name: user.name,
      email: user.email,
      pictureUrl: user.picture
    };

    jwt.sign(payload, secretOrKey, { expiresIn: 3600 }, (err, token) => {
      res.json({ success: true, token: "Bearer " + token });
    });
  });
});

我非常讨厌我必须使用两次身份验证代码,但它是有效的。如果有人能推荐此代码的重构版本,我们将不胜感激。

感谢您的提示。我现在将.save((err,obj)=>{return obj})中的用户作为对象返回。但是,之后仍然无法继续登录过程。@Ruham-好吧,使用带有
.save()
的回调并不容易。这就是为什么我将承诺与
let result=wait user.save()一起使用的原因。我提出了一个如何做的建议。如果您想忽略我的建议,这是您的选择,但我向您展示了一种方法。我尝试了您的版本,但由于某种原因(500服务器错误)它不起作用。我发布了工作版本,但我不喜欢现在的代码。@Ruham-好吧,我在回答中说,您必须查看
中的
结果
,让result=wait user.save()
,并找出结果中您的
facebook id
的确切位置,因为我自己无法查看数据。看起来在你的版本中,你可以设置
user.id=result.backbookId
,然后它就会工作,所以我也编辑了我的。你可以试试。@Ruham-好的,我在回答中更新了我的版本和你的版本的改进版本。我在它丢失的地方添加了一些错误处理。