使用Passport.js注册用户后无法持久化会话的求助
Passport.js 认证失效问题:注册后刷新/跳转页面需重新登录
注:目前仅使用json-server测试,未接入数据库。
注册路由功能正常,注册后能重定向到/posts且req.user存在新用户,但刷新页面或跳转后返回会被重定向到登录页,需重新登录。
注册路由代码
app.post('/signup', async (req, res) => { const { email, username, password } = req.body; if (!email || !username || !password) { req.flash('error', 'Missing credentials'); res.redirect('/signup'); return; } const response = await fetch('http://localhost:3000/users', { method: 'post', body: JSON.stringify(req.body), headers: { 'Content-Type': 'application/json' }, }); const data = await response.json(); req.login(req.body, (err) => { if (err) { return next(err); } res.redirect('/posts'); }); });
Posts页面路由代码
app.get('/posts/', async (req, res) => { if (req.isAuthenticated()) { console.log(req.user); const response = await fetch('http://localhost:3000/posts'); const data = await response.json(); const sortedData = data.toSorted( (a, b) => new Date(b.date) - new Date(a.date) ); const users = await getUsers(); const newData = sortedData.map((post) => ({ ...post, author: users.find((user) => parseInt(user.id) === post.userId).username, })); res.render('posts.ejs', { posts: newData, user: req.user }); } else { res.redirect('/signin'); } });
Passport配置代码
passport.use( new LocalStrategy(async function verify(username, password, cb) { const users = await getUsers(); const matchedUser = users.find((user) => user.username === username); if (!matchedUser || matchedUser.password !== password) { return cb(null, false, { message: 'Incorrect username or password.' }); } return cb(null, matchedUser); }) ); passport.serializeUser(function (user, cb) { cb(null, user); }); passport.deserializeUser(function (user, cb) { cb(null, user); });
Session与Cookie配置代码
app.use( session({ secret: 'secretStringForNow', resave: false, saveUninitialized: false, cookie: { maxAge: 1000 * 60 * 60 * 24, }, }) ); app.use(passport.initialize()); app.use(passport.session());
问题原因与解决方法
核心问题
- 注册时调用
req.login(req.body, ...)传入的是前端提交的原始请求体,而非json-server返回的带id的完整用户对象。Passport序列化后存入session的对象缺少唯一标识,后续反序列化时无法与登录流程中获取的用户匹配,导致认证失效。 - 直接序列化整个用户对象,易出现session数据序列化/反序列化的兼容性问题,且存储效率低。
saveUninitialized: false可能导致新用户的session未被持久化。
解决步骤
使用完整用户对象登录
修改注册路由中req.login的参数,替换为json-server返回的data(带id的用户对象):// 原代码 // req.login(req.body, (err) => { // 修改为 req.login(data, (err) => { if (err) { return next(err); } res.redirect('/posts'); });优化序列化与反序列化逻辑
仅存储用户唯一标识(id),反序列化时通过id重新从json-server获取用户:// 修改serializeUser passport.serializeUser(function (user, cb) { cb(null, user.id); // 只存储用户id }); // 修改deserializeUser passport.deserializeUser(async function (id, cb) { const users = await getUsers(); const user = users.find(u => u.id === id); cb(null, user); // 通过id获取完整用户对象 });调整session配置
将saveUninitialized改为true,确保新用户的session被持久化:app.use( session({ secret: 'secretStringForNow', resave: false, saveUninitialized: true, cookie: { maxAge: 1000 * 60 * 60 * 24, }, }) );
验证效果
修改后重新注册用户,刷新/posts页面或跳转其他页面再返回,应能保持登录状态,req.isAuthenticated()返回true。
内容的提问来源于stack exchange,提问作者bwongyh
相关产品推荐
相关产品推荐

