集成express-mysql-session后req.isAuthenticated()为false导致登录失败
我正在开发一个基于Express、Passport、express-mysql-session的简易登录应用。未集成MySQLSessionStore时,调试显示req对象已正确设置用户,req.isAuthenticated()返回true,登录功能正常;但集成该会话存储并清空sessions表后登录,虽然会话ID一致,但跳转至安全页面时req.isAuthenticated()返回false,req对象中缺失user对象。
我已经检查了index.js中app.use(session())、passport.initialize()、passport.session()的中间件顺序,也配置了cookieParser密钥,但仍不清楚MySQLSessionStore为何会影响Passport的serializeUser与deserializeUser流程。
相关代码如下:
const express = require("express"); const cookieParser=require('cookie-parser') const session = require("express-session"); const path = require("path"); const app = express(); const MySQLStore=require('express-mysql-session')(session) const flash = require("connect-flash"); const passport = require("passport"); app.set("views", path.join(__dirname, "views")); app.set("view-engine", "ejs"); app.use('/static', express.static(path.join(__dirname, 'public'))) app.use(express.json()); app.use(express.urlencoded({ extended: false })); const env = process.env.NODE_ENV || 'development'; const config = require('./config/config.json')[env]; const { loginCheck } = require("./config/passport-config"); loginCheck(passport); var options ={ host:'localhost', port:3306, user:'root', password:'root', database:'logindb' } const oneYear=1000*60*60*24*365 const sessionStore=new MySQLStore(options) app.use( session({ key:'session_cookie_name', store:sessionStore, secret: "LoginAppSecret", saveUninitialized: false, resave: false, cookie: {maxAge:oneYear,httpOnly:true} }) ); app.use(cookieParser("LoginAppSecret")) app.use(flash()); app.use(function (request, response, next) { response.locals.message = request.flash("message"); response.locals.errors = request.flash("error"); next(); }); // Passport middleware app.use(passport.initialize()); app.use(passport.session()); const port = 3000; const swaggerUi = require("swagger-ui-express"), swaggerDocument = require("./swagger/swagger"); //Routes app.use("/", require("./router/login")); app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); app.listen(port,"localhost", () => { console.log(" Server running!!"); });
登录失败后的会话记录:
- {"cookie":{"originalMaxAge":31536000000,"expires":"2023-11-05T05:25:53.426Z","httpOnly":true,"path":"/"},"flash":{}}
- {"cookie":{"originalMaxAge":31536000000,"expires":"2023-11-05T05:26:00.122Z","httpOnly":true,"path":"/"},"flash":{},"passport":{"user":2}}
- {"cookie":{"originalMaxAge":31536000000,"expires":"2023-11-05T05:26:00.138Z","httpOnly":true,"path":"/"},"flash":{"message":["Please log in to view that resource"]}}
问题排查与解决方案
1. 修正中间件加载顺序
当前cookieParser在session之后加载,会导致session无法正确解析cookie。正确的加载顺序必须是:
- 先加载
cookieParser - 再初始化
session - 最后加载Passport相关中间件
修改后的代码片段:
// 先加载cookieParser app.use(cookieParser("LoginAppSecret")) // 再初始化session app.use( session({ key:'session_cookie_name', store:sessionStore, secret: "LoginAppSecret", saveUninitialized: false, resave: false, cookie: {maxAge:oneYear,httpOnly:true} }) ); // 后续中间件 app.use(flash()); app.use(function (request, response, next) { response.locals.message = request.flash("message"); response.locals.errors = request.flash("error"); next(); }); app.use(passport.initialize()); app.use(passport.session());
2. 处理异步会话存储延迟
express-mysql-session是异步写入会话的,可能出现会话未完成写入就跳转的情况。可以在登录成功后手动触发会话保存:
// 登录路由示例 router.post('/login', passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }), (req, res) => { // 确保会话写入数据库后再跳转 req.session.save((err) => { if (err) console.error(err); res.redirect('/dashboard'); }); });
3. 检查数据库表字段类型
确认sessions表的session_data字段类型为TEXT或LONGTEXT,如果字段长度不足(比如用了VARCHAR),会导致会话数据被截断,Passport无法读取用户信息。
4. 确认密钥一致性
确保session的secret和cookieParser的密钥完全一致,当前代码中两者均为"LoginAppSecret",后续修改需保持同步。
内容的提问来源于stack exchange,提问作者patil

