如何使用connect-mongodb-session实现两个Node应用共享同一MongoDB会话存储
两个应用要实现同一份会话的跨服务校验,核心是必须对齐所有影响会话识别、签名、存储的配置项,哪怕连接同一个Mongo实例,配置不一致也无法正常完成校验。
需要对齐的核心配置项
- 固化会话签名密钥,禁止动态生成
express-session会用配置的secret对Cookie中存储的会话ID做HMAC签名,防止客户端伪造会话ID。当前两个应用都用uuidv4()每次启动随机生成secret,会出现最常见的验签失败问题:认证服务签名生成的合法sidCookie,到仪表盘服务后会被自身的随机密钥判定为非法签名,直接被丢弃。
正确做法是把secret抽成两个应用可共同读取的固定值,比如存在共用的环境变量中,不要用动态生成的UUID。 - 统一会话Cookie的名称
认证服务当前设置的会话Cookie名是
sid,仪表盘应用注释掉了name配置,会默认使用express-session内置的Cookie名connect.sid,和浏览器传来的Cookie名不匹配,根本无法读取到会话ID。 - 对齐MongoDB会话存储实例
两个应用都需要实例化指向同一个Mongo连接串、同一个
sessions集合的connect-mongodb-session对象,否则仪表盘应用根本无法访问到认证服务写入的会话数据。 - 对齐Cookie的作用域配置
保证
path、domain配置和认证服务完全一致,让浏览器能够将sidCookie同时发送到两个应用的访问地址。如果两个应用是同主机不同端口(如认证服务跑在3000端口,仪表盘跑在3001端口),当前domain: 'localhost'、path: '/'的配置是可以正常跨端口传递Cookie的,不需要额外调整。
修正后的app_dashboard.js 会话配置
// 文件顶部先引入依赖 const session = require('express-session'); const mongoDbStore = require('connect-mongodb-session')(session); // 实例化和认证服务完全一致的Mongo会话存储 const store = new mongoDbStore({ uri: MONGODB_URI, // 和server_app.js使用完全相同的Mongo连接地址 collection: 'sessions' // 和server_app.js使用完全相同的集合名 }); app.use(session({ // 替换为两个应用共用的固定密钥,禁止用uuidv4()动态生成 secret: '与server_app.js完全相同的固化密钥值', store: store, // 保持Cookie名称和认证服务一致 name: 'sid', // 对齐Cookie作用域配置 cookie: { path: '/', domain: 'localhost', // 可根据业务需要补充maxAge参数,和认证服务配置保持一致 }, resave: false, saveUninitialized: false }))
常见踩坑提示
- 完成上述配置后,不需要手动转发会话ID:只要Cookie作用域覆盖两个应用的访问地址,浏览器会自动将合法的
sidCookie随请求发送到仪表盘服务,无需做额外的参数透传逻辑。 - 生产环境如果两个应用部署在同根域名下的不同子域名(如认证服务在
auth.xxx.com,仪表盘在dashboard.xxx.com),需要将Cookie的domain设置为.xxx.com,才能实现跨子域名的Cookie传递,单独配置某一个子域名会导致Cookie无法跨服务传递。 - 建议两个应用保持相同的
express-session、connect-mongodb-session依赖版本,避免因中间件内部的会话序列化格式差异,出现明明存在Mongo库里的会话却读不出来的兼容问题。 - 本地开发调试时注意不要设置
cookie.secure为true,HTTP协议访问的场景下,开启secure会导致浏览器完全不存储/传递Cookie,阻断正常会话流程。
内容的提问来源于stack exchange,提问作者Pranay Chandale

