2

当我尝试使用 将 Google OAuth 实施到我的节点应用程序中passport-google-oauth20时,我遇到了问题。

每当我尝试使用以下代码第一次登录机密页面时,我无法进行身份验证并被重定向到该/login页面,Cannot set headers after they are sent to the client即使newUser已保存在 mongoDB 中,也会在序列化用户的行中收到错误消息。

但是,我可以在第二次登录尝试时成功验证并登录到机密页面。

发生错误的幕后发生了什么?第一次登录尝试时如何成功验证用户身份?

我也提到了这个问答

passport.use(new GoogleStrategy({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: "http://localhost:3000/auth/google/secrets"
    },
    (accessToken, refreshToken, profile, done) => {
      User.findOne({ googleId: profile.id }, (err, foundUser) => {
        if (err) return done(err);
        if (!foundUser) {
          const newUser = new User({
            googleId: profile.id
          });

          newUser.save((err, savedUser) => {
            if (err) throw err;
            return done(null, savedUser);
          });
        }
        return done(null, foundUser);
      });
    }
));
passport.serializeUser((user, done) => {
  done(null, user.id);     ///// The error occurs at this line /////
});

passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
    done(err, user);
  });
});
app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile'] }));

app.get(
  "/auth/google/secrets",
  passport.authenticate("google", {
    successRedirect: "/secrets",
    failureRedirect: "/login"
  })
);

app.get("/secrets", (req, res) => {
  if (req.isAuthenticated()) return res.render("secrets");
  res.redirect("/login");
});
4

1 回答 1

0

我看到的问题在验证回调中。调用return done(null, savedUser)将异步发生。这意味着程序将首先调用return done(null, foundUser)然后在保存调用之后return done(null, savedUser)

为了解决这个问题,我建议重构验证回调以使用 async/await。这使得推理更容易,并减少了来自冲突回调的竞争条件的机会。

示例重构:

async (accessToken, refreshToken, profile, done) => {
  try {
    let foundUser = await User.findOne({ googleId: profile.id });
    
    if (!foundUser) {
      const newUser = new User({
        googleId: profile.id
      });

      await newUser.save();
      return done(null, newUser);
    }

    return done(null, foundUser);
  } catch (err) {
    return done(err);
  }
}));
于 2021-02-17T01:23:50.720 回答