当我尝试使用' passport-google-oauth20 '登录时,'发送到客户端后无法设置标头'



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

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

然而,我可以成功地验证并登录到secrets页面的第二次登录尝试。

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

我也提到了这个问题。

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");
});

我看到的问题是在验证回调。调用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);
}
}));

最新更新