express-session
是 Express 框架的一个中间件,用于处理会话数据。而 connect-mongo
是一个将 express-session
的会话数据存储在 MongoDB 中的第三方库。通过 connect-mongo
,你可以轻松地将用户会话持久化到 MongoDB 数据库中,这对于需要跨多个请求或服务器实例保持用户状态的应用非常有用。
一、下面是一个使用 express-session
和 connect-mongo
将会话数据存储在 MongoDB 中的示例:
-
安装依赖
首先,你需要安装
express
、express-session
和connect-mongo
。npm install express express-session connect-mongo mongoose
注意:虽然
connect-mongo
不直接依赖于mongoose
,但使用mongoose
可以帮助你更方便地管理 MongoDB 连接。然而,在这个示例中,我们将直接使用connect-mongo
提供的 MongoDB 连接选项。 -
配置 Express 应用
接下来,在你的 Express 应用中配置
express-session
和connect-mongo
。const express = require('express'); const session = require('express-session'); const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); const app = express(); // 连接到 MongoDB 数据库 mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true, // 如果你使用的是 MongoDB Atlas 或其他需要认证的 MongoDB 服务, // 你可能还需要提供用户名和密码,如下所示: // auth: { user: 'yourUsername', password: 'yourPassword' } }); mongoose.connection.once('open', () => { console.log('Connected to MongoDB'); }); const mongoStoreOptions = { mongooseConnection: mongoose.connection, collection: 'sessions', // 会话数据将存储在这个集合中 ttl: 24 * 60 * 60, // 会话在 MongoDB 中的存活时间(秒),这里设置为1天 autoCommit: false, // 如果设置为true,则每次请求都会自动提交会话更改(可能会增加数据库负载) autoRemove: 'interval', // 自动清理过期会话的策略,'interval'表示按时间间隔清理 autoRemoveInterval: 10 // 自动清理过期会话的时间间隔(分钟) }; const mongoStoreInstance = new MongoStore(mongoStoreOptions); app.use(session({ secret: 'your_secret_key', // 用于签名会话ID cookie的密钥 resave: false, // 强制将会话保存回会话存储,即使会话没有更改 saveUninitialized: false, // 强制将未初始化的会话保存到存储中 store: mongoStoreInstance, // 使用 MongoDB 存储会话 cookie: { secure: false, // 如果你的应用通过 HTTPS 提供服务,则应该设置为 true httpOnly: true, // 阻止客户端 JavaScript 访问 cookie maxAge: 24 * 60 * 60 * 1000, // cookie 的存活时间(毫秒),这里也设置为1天 }, })); // 示例路由 app.get('/', (req, res) => { if (req.session.views) { req.session.views++; res.send(`You have visited this page ${req.session.views} times`); } else { req.session.views = 1; res.send('Welcome to the session demo. Refresh!'); } }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
-
运行应用
确保你的 MongoDB 实例正在运行,并且你已经在上面配置的数据库中创建了必要的集合(虽然
connect-mongo
会在需要时自动创建集合)。然后运行你的 Express 应用。node app.js
现在,当你访问
http://localhost:3000
时,express-session
会使用connect-mongo
和 MongoDB 来存储会话数据。每次你刷新页面时,会话中的views
计数器都会增加。
注意事项
- 在生产环境中,你应该通过 HTTPS 提供你的应用,并将
cookie.secure
设置为true
,以确保会话 cookie 的安全性。 secret
应该是一个足够复杂且难以猜测的字符串,以确保会话 ID 的签名安全性。- 你可以根据需要调整会话的过期时间和其他配置选项。
- 确保你的 MongoDB 数据库连接字符串和其他配置信息是正确的,并且你的数据库实例是可访问的。
- 如果你使用的是 MongoDB Atlas 或其他需要认证的 MongoDB 服务,请确保提供了正确的认证信息。
二、下面是一个使用 express-session
和 connect-mongo
实现用户登录会话的简单示例:
这个示例将展示如何设置会话中间件、处理用户登录请求,并在会话中存储用户信息。
首先,确保你已经安装了必要的依赖:
npm install express express-session connect-mongo mongoose body-parser
然后,创建一个 Express 应用,并配置会话中间件和用户登录逻辑:
const express = require('express');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const app = express();
// MongoDB 连接配置
mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connection.once('open', () => {
console.log('Connected to MongoDB');
});
// 会话存储配置
const mongoStoreOptions = {
mongooseConnection: mongoose.connection,
collection: 'sessions',
ttl: 24 * 60 * 60, // 会话在 MongoDB 中的存活时间(秒)
};
const mongoStoreInstance = new MongoStore(mongoStoreOptions);
// 会话中间件配置
app.use(session({
secret: 'your_secret_key', // 用于签名会话ID cookie的密钥
resave: false,
saveUninitialized: false,
store: mongoStoreInstance,
cookie: {
secure: false, // 在生产环境中应设置为 true(通过 HTTPS 提供服务)
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // cookie 的存活时间(毫秒)
},
}));
// 解析 JSON 请求体
app.use(bodyParser.json());
// 示例用户模型(仅用于演示,实际中应使用更复杂的用户验证和存储逻辑)
const UserSchema = new mongoose.Schema({
username: String,
password: String, // 注意:在生产环境中,密码应加密存储
});
const User = mongoose.model('User', UserSchema);
// 用户登录路由
app.post('/login', async (req, res) => {
const { username, password } = req.body;
// 在这里执行用户验证逻辑(例如,查询数据库并比较密码)
// 注意:这个示例中的密码验证是非常不安全的,仅用于演示
const user = await User.findOne({ username, password });
if (user) {
// 验证成功,将用户信息存储在会话中
req.session.user = { username: user.username };
res.send({ message: 'Login successful', user: req.session.user });
} else {
// 验证失败,返回错误消息
res.status(401).send({ message: 'Invalid username or password' });
}
});
// 受保护的路由示例
app.get('/protected', (req, res) => {
if (req.session.user) {
// 用户已登录,返回受保护的内容
res.send({ message: 'Welcome to the protected route', user: req.session.user });
} else {
// 用户未登录,重定向到登录页面或返回错误消息
res.status(403).send({ message: 'You are not authorized to access this route' });
}
});
// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
注意事项:
-
安全性:上述示例中的密码验证是非常不安全的,因为它直接将明文密码与数据库中的密码进行比较。在实际应用中,你应该使用密码哈希和加盐技术来存储和验证密码。
-
HTTPS:在生产环境中,你应该通过 HTTPS 提供你的应用,并将
cookie.secure
设置为true
,以确保会话 cookie 的安全性。 -
用户模型:上述示例中的用户模型非常简单,仅包含用户名和密码。在实际应用中,你可能需要更复杂的用户模型,包括额外的字段(如电子邮件、电话号码、角色等)以及更复杂的验证逻辑。
-
会话过期:你可以根据需要调整会话的过期时间(
ttl
)和其他配置选项。 -
错误处理:上述示例中的错误处理非常简单。在实际应用中,你应该有更完善的错误处理机制来处理各种可能的异常情况。
-
数据库连接:确保你的 MongoDB 数据库连接字符串和其他配置信息是正确的,并且你的数据库实例是可访问的。如果使用的是 MongoDB Atlas 或其他需要认证的 MongoDB 服务,请确保提供了正确的认证信息。