You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:35:56