用户序列化失败及Passport登录问题求助
Hey there, let's break down your two questions and fix that serialization issue step by step!
1. Why does logging user return true instead of the user object?
This is a classic mix-up with what you're passing to Passport's done function. Look at this section of your Local Strategy code:
bcrypt.compare(password, user_obj.password, (err, varifiedUser) => { if (err) throw new Error(err); else if (varifiedUser) { return done(null, varifiedUser); // ← Here's the mistake! } else { return done(null, false, { message: "Incorrect password!" }); } });
The varifiedUser variable from bcrypt.compare() is just a boolean (true/false) that confirms if the password matches—it's not the actual user object. When you pass this boolean to done(), Passport takes that true value and passes it straight to serializeUser, which is why your logs show true instead of a user document.
Quick Fix: Pass the actual user object (user_obj) to done() when authentication succeeds:
else if (varifiedUser) { return done(null, user_obj); // Pass the full user object here }
2. Why pass user.id instead of MongoDB's default user._id in serializeUser?
First, let's clarify: MongoDB uses _id as the default primary key for all documents. If you haven't explicitly added a virtual id field to your Mongoose schema, user.id doesn't exist—you should be using user._id instead.
Looking at your deserializeUser code, there are a couple more critical errors amplifying this confusion:
passport.deserializeUser((user, done) => { // Parameter name is wrong usermodel.findById(user.id, (err, id) => { // Querying for a non-existent `user.id` if (!err) { done(null, user); // Passing the ID back instead of the fetched user } else { done(err); } }); });
- The first parameter to
deserializeUseris the ID you passed fromserializeUser, not a user object—rename it toidfor clarity. - You're trying to query by
user.id, but if you serializeduser._id, you should use that value directly infindById(). - Finally, you're passing the original ID back instead of the actual user document you fetched from the database.
Corrected serializeUser and deserializeUser:
passport.serializeUser((user, done) => { console.log("user object serialize", user); done(null, user._id); // Use MongoDB's default _id field }); passport.deserializeUser((id, done) => { usermodel.findById(id, (err, foundUser) => { if (err) { done(err); } else { done(null, foundUser); // Pass the fetched user object to done() } }); });
If you do want to use user.id (a common practice for cleaner API responses), you can add a virtual field to your Mongoose schema to map _id to id:
const userSchema = new mongoose.Schema({ // Your existing schema fields (email, password, etc.) }); // Add virtual `id` field that returns a string version of _id userSchema.virtual('id').get(function() { return this._id.toHexString(); }); // Ensure virtual fields are included when converting documents to JSON userSchema.set('toJSON', { virtuals: true }); const usermodel = mongoose.model('User', userSchema);
With this setup, user.id will work exactly like user._id but as a plain string, which plays nicely with Passport.
Full Corrected Authentication Code
Here's your code with all fixes applied, plus a small improvement to error handling:
passport.use(new passportLocal({ usernameField: 'email' }, (email, password, done) => { console.log(email, password); usermodel.findOne({ email: email }, (err, user_obj) => { console.log("user object get by database", user_obj) if (err) return done(err); // Use done() instead of throwing errors (Passport expects this) if (!user_obj) { return done(null, false, { message: "There is no user with that email." }); } bcrypt.compare(password, user_obj.password, (err, isMatch) => { if (err) return done(err); if (isMatch) { return done(null, user_obj); // Pass the full user object } else { return done(null, false, { message: "Incorrect password!" }); } }); }); })); passport.serializeUser((user, done) => { console.log("user object serialize", user); done(null, user._id); }); passport.deserializeUser((id, done) => { usermodel.findById(id, (err, foundUser) => { done(err, foundUser); // Simplified error handling }); }); router.post("/login", passport.authenticate('local', { successRedirect: '/auth/quiz', failureRedirect: '/auth/login' }));
内容的提问来源于stack exchange,提问作者Priyanshu Sharma

