express-session + Redis做会话管理
使用express-session + Redis可以快速实现可靠的会话管理,并具有灵活性、扩展性和安全性等优点,适用于大型的Web应用程序。
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser')
const { check, validationResult } = require('express-validator');
const passwordValidator = require('password-validator');
import RedisStore from "connect-redis"
import {createClient} from "redis"
const app = express();
const hostname = '127.0.0.1';
const port = 3000;
// Initialize client.
let redisClient = createClient()
redisClient.connect().catch(console.error)
// Initialize store.
let redisStore = new RedisStore({
client: redisClient,
prefix: "myapp:",
})
app.use(cookieParser());
// Initialize sesssion storage.
app.use(
session({
store: redisStore,
resave: false, // required: force lightweight session keep alive (touch)
saveUninitialized: false, // recommended: only save session when data exists
secret: "keyboard cat",
cookie: {
httpOnly: true,//一个布尔值,表示是否将cookie标记为"HttpOnly",这样cookie就不能被JavaScript代码访问,从而防止了一些攻击方式。
secure: false,//一个布尔值,表示是否将cookie标记为"Secure",这样cookie只能通过HTTPS协议发送,从而保证了安全性。
maxAge: 1000 * 60 * 60 * 2 // 1 day
}
})
)
app.use(express.json()) // 这个中间件用于解析请求体中的JSON格式的数据
app.use(express.urlencoded({ extended: true })) //这个中间件用于解析请求体中的"application/x-www-form-urlencoded"格式的数据
function logParams(req, res, next) {
console.log('Request parameters:', req.params);
console.log('Request query:', req.query);
console.log('Request body:', req.body);
console.log("Request session:", req.session);
next();
}
app.use(logParams);
// Initialize password validator.
const schema = new passwordValidator();
schema
.is().min(8) // 长度不能小于8位
.has().uppercase() //必须有大写字母
.has().lowercase() // 必须有小写字母
.has().digits() // 必须有数字
.has().symbols() // 必须有符号
.not().spaces(); // 不能有空格
app.post('/signup', [
check('username').isLength({ min: 1 }).withMessage('用户名不能为空'),
check('password').custom((value, {req}) => {
if (!schema.validate(value)) {
throw new Error('密码必须包含至少一个大写字母,一个小写字母,一个数字,一个特殊字符,且长度不少于8个字符');
}
return true;
}),
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
// ...
// 处理用户注册逻辑
// ...
res.send('注册成功');
});
app.post('/login',
[
check('name').isLength({ min: 1 }).withMessage('姓名是必填项')
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
// 登录成功后将用户信息存储在 session 中
req.session.user = {id: 1, username: 'my-username'};
res.send('登录成功');
});
app.get('/logout', (req, res) => {
req.session.destroy(err => {
if (err) {
console.error('Failed to destroy session:', err)
} else {
res.redirect('/login')
}
})
})
// 后续路由就可以取用户信息
app.get('/user', (req, res) => {
// 从 session 中获取用户信息
const user = req.session.user;
if (!user) {
return res.status(401).send('未登录');
}
res.send(`当前登录用户:${user.username}`);
});
// 启动应用程序
app.listen(port, hostname, () => {
console.log(`Server running at http://``{hostname}:``{port}/`);
});
express-session 做会话有什么优缺点
优点:
- 简单易用:express-session提供了一个简单的API,可以快速实现会话的管理和存储。
- 可扩展性强:express-session可以与各种session存储引擎(如redis、mongodb、mysql等)集成,可以灵活地选择最适合自己应用的存储方式。
- 安全性高:express-session自带的安全机制可以防止会话劫持和伪造,提高了应用程序的安全性。
缺点:
- 存储开销:express-session的存储开销比较大,会占用一定的内存和磁盘空间,特别是在高并发的情况下,存储开销会更大。
- 配置麻烦:如果需要使用session store,需要对session store的配置和使用进行详细的了解和配置,有一定的学习成本。
- 不支持跨域:express-session不支持跨域访问,如果需要实现跨域访问的会话管理,需要进行额外的配置和处理。
综合来看,express-session是一个功能强大、可扩展性强、安全性高的会话管理中间件,但在使用时需要考虑存储开销和配置的复杂性。