Passport.js反序列化用户返回null问题求助
Passport.js反序列化用户返回null问题
我用Passport.js实现身份验证,之前运行完全正常,现在突然出现反序列化用户时返回null的情况——会话中明明存在对应用户ID,但就是查不到用户。更奇怪的是,我复制了相同的认证逻辑,只修改了模型名称,另一个控制器却能正常运行。
相关代码
import express from 'express'; import session from 'express-session'; import passport from 'passport'; import LocalStrategy from 'passport-local'; import { PoliceStation } from '../Models/policestation.model.js'; class PoliceController { constructor() { this.router = express.Router(); this.initializePassport(); this.initializeRoutes(); } initializePassport() { console.log('Initializing passport 1') passport.use('policestation-local', new LocalStrategy(async (username, password, done) => { try { console.log('Incoming name:', username); console.log('Incoming password:', password); const user = await PoliceStation.findOne({ name: username, password: password }); if (!user) { console.log('User not found'); return done(null, false, { message: 'Incorrect username or password' }); } console.log('User found:', user); return done(null, user); } catch (error) { console.error('Error in LocalStrategy:', error.message); return done(error); } }) ); passport.serializeUser((user, done) => { console.log('Serialize User:', user.id); done(null, user.id); }); passport.deserializeUser(async (id, done) => { console.log('Deserialize User ID:', id); try { const user = await PoliceStation.findById(id); console.log('Deserialized User:', user); done(null, user); } catch (error) { console.error('Deserialize User Error:', error); done(error); } }); } initializeRoutes() { this.router.use( session({ secret: '12345', resave: false, saveUninitialized: true, cookie: { httpOnly: true, secure: false, maxAge: 7 * 24 * 60 * 60 * 1000, }, }) ); this.router.use(passport.initialize()); this.router.use(passport.session()); const requireLogin = (req, res, next) => { console.log('Authentication Status:', req.isAuthenticated()); console.log('User Object:', req.user); if (req.isAuthenticated()) { next(); } else { res.status(401).send('Unauthorized'); } }; this.router.post('/login', passport.authenticate('policestation-local'), (req, res) => { if (req.isAuthenticated()) { const user = req.user; console.log('Authenticated User:', user); console.log('Session Data:', req.session); res.status(200).json({ message: 'Login successful', user }); } else { console.log('Authentication failed'); res.status(401).json({ message: 'Login failed' }); } }); this.router.get('/checklogin', (req, res) => { if (req.isAuthenticated()) { console.log('User is authenticated:', req.user); res.json({ loggedIn: true, user: req.user }); } else { console.log('User is not authenticated'); res.json({ loggedIn: false }); } }); this.router.get('/', this.hello.bind(this)); this.router.post('/logout', this.logout.bind(this)); this.router.get('/map/:_id', requireLogin, this.getMap.bind(this)); this.router.get('/officer/:_id', requireLogin, this.getPoliceOfficers.bind(this)); } async hello(req, res) { res.send('Hello World!'); } logout(req, res) { req.session.destroy((err) => { if (err) { console.error('Session destroy error:', err); return res.status(500).send('Internal Server Error'); } res.send('Logged out successfully'); }); } async getMap(req, res) { try { const userId = req.params._id; const userInfo = await PoliceStation.findById(userId); if (!userInfo) { return res.status(404).json({ error: 'User not found' }); } const userLocation = userInfo.location; res.json({ location: userLocation }); } catch (error) { console.log('Map Error:', error); res.status(500).json({ error: 'Internal Server Error' }); } } async getPoliceOfficers(req, res) { try { const userId = req.params._id; const userInfo = await PoliceStation.findById(userId).populate('policeOfficers').exec(); if (!userInfo) { return res.status(404).json({ error: 'User not found' }); } const policeOfficers = userInfo.policeOfficers || []; res.json({ policeOfficers }); } catch (error) { console.log('Get Police Officers Error:', error); res.status(500).json({ error: 'Internal Server Error' }); } } } export default PoliceController;
控制台输出
Incoming name: Bani Gala Incoming password: 12345678 User found: { location: { type: 'Point', coordinates: [ 73.14266502857208, 33.67536763416153 ] }, _id: new ObjectId("646e2f653433e58b4b36bbc9"), name: 'Bani Gala', address: 'Bani Gala, Islamabad', phone: 519255339, password: '12345678', rating: 5, __v: 9, policeOfficers: [ new ObjectId("646e3bf76c974f42bcbb055d"), new ObjectId("646f67acdff8e98bf7fcf530"), new ObjectId("646fc7aa88960bcfdc00352a"), new ObjectId("646fc7b788960bcfdc003532"), new ObjectId("6473905b525377ad83c76d27"), new ObjectId("652ba58332ff7f5df0014395"), new ObjectId("652d46a4c1f1ea9992302b77"), new ObjectId("652d6f88c34a3964bc9ebae4"), new ObjectId("652d7099c34a3964bc9ebb04") ] } Serialize User: 646e2f653433e58b4b36bbc9 Authenticated User: { location: { type: 'Point', coordinates: [ 73.14266502857208, 33.67536763416153 ] }, _id: new ObjectId("646e2f653433e58b4b36bbc9"), name: 'Bani Gala', address: 'Bani Gala, Islamabad', phone: 519255339, password: '12345678', rating: 5, __v: 9, policeOfficers: [ new ObjectId("646e3bf76c974f42bcbb055d"), new ObjectId("646f67acdff8e98bf7fcf530"), new ObjectId("646fc7aa88960bcfdc00352a"), new ObjectId("646fc7b788960bcfdc003532"), new ObjectId("6473905b525377ad83c76d27"), new ObjectId("652ba58332ff7f5df0014395"), new ObjectId("652d46a4c1f1ea9992302b77"), new ObjectId("652d6f88c34a3964bc9ebae4"), new ObjectId("652d7099c34a3964bc9ebb04") ] } Session Data: Session { cookie: { path: '/', _expires: 2023-12-03T14:25:04.606Z, originalMaxAge: 604800000, httpOnly: true, secure: false }, passport: { user: '646e2f653433e58b4b36bbc9' } } Deserialize User ID: 646e2f653433e58b4b36bbc9 Deserialized User: null User is not authenticated
其他控制器情况
我创建了另一个控制器,完全复制了当前的认证逻辑,只修改了模型名称,那个控制器能正常完成序列化和反序列化,没有任何问题。
排查与解决建议
1. 强制转换ObjectId类型
Mongoose自动转换字符串ID到ObjectId可能失效,手动转换试试:
// 先导入mongoose import mongoose from 'mongoose'; // 修改反序列化函数 passport.deserializeUser(async (id, done) => { console.log('Deserialize User ID:', id); try { // 手动转换为ObjectId const user = await PoliceStation.findById(new mongoose.Types.ObjectId(id)); console.log('Deserialized User:', user); done(null, user); } catch (error) { console.error('Deserialize User Error:', error); done(error); } });
2. 检查模型导入是否正确
确认policestation.model.js的导出方式:
- 如果模型是
export default PoliceStation;,则导入应该用import PoliceStation from '../Models/policestation.model.js';,而不是命名导入{ PoliceStation } - 打印模型验证:在
initializePassport开头加console.log('PoliceStation Model:', PoliceStation);,如果输出不是Mongoose模型对象,说明导入错误。
3. 避免Passport全局实例冲突
多个控制器重复初始化Passport会导致全局的serializeUser/deserializeUser被覆盖。解决办法:
- 把Passport初始化移到全局(比如app.js),每个控制器只注册自己的策略
- 或者使用Passport的命名序列化/反序列化(仅Passport 0.6+支持):
// 序列化时指定策略名 passport.serializeUser('policestation-local', (user, done) => { done(null, user.id); }); // 反序列化时指定策略名 passport.deserializeUser('policestation-local', async (id, done) => { // ...查询逻辑 });
4. 直接验证数据库查询
在终端或单独脚本中执行查询,确认数据存在:
import mongoose from 'mongoose'; import { PoliceStation } from './Models/policestation.model.js'; // 先连接数据库 mongoose.connect('你的数据库连接字符串'); async function testQuery() { const user = await PoliceStation.findById('646e2f653433e58b4b36bbc9'); console.log('数据库查询结果:', user); } testQuery();
如果查询结果是null,说明数据库中该ID的文档已被删除;如果能查到,说明代码中的模型或连接有问题。
5. 检查数据库连接
确认当前控制器使用的Mongoose连接是否指向正确的数据库,避免连接到测试库或其他环境的数据库。
内容的提问来源于stack exchange,提问作者B1 FOOTBALL
相关产品推荐
相关产品推荐

