Koa 中 Cookie 和 Session 管理的实现方法
Koa 的 Cookie 和 Session 管理是构建 Web 应用的基础功能,Koa 核心提供了 Cookie 操作,而 Session 需要通过中间件实现。1. Cookie 操作:Koa 核心内置了 Cookie 功能,通过 ctx.cookies 对象进行操作。设置 Cookie:app.use(async (ctx) => { // 基本设置 ctx.cookies.set('name', 'value'); // 带选项的设置 ctx.cookies.set('username', 'john', { maxAge: 3600000, // 有效期(毫秒) expires: new Date('2025-12-31'), // 过期时间 path: '/', // 路径 domain: '.example.com', // 域名 secure: true, // 仅 HTTPS httpOnly: true, // 仅 HTTP,防止 XSS sameSite: 'strict', // CSRF 保护 signed: true // 签名 Cookie }); ctx.body = 'Cookie set';});获取 Cookie:app.use(async (ctx) => { const username = ctx.cookies.get('username'); ctx.body = `Hello ${username}`;});删除 Cookie:app.use(async (ctx) => { ctx.cookies.set('username', null, { maxAge: 0, path: '/' }); ctx.body = 'Cookie deleted';});2. Session 管理:使用 koa-session 中间件实现 Session 功能。安装:npm install koa-session基本配置:const session = require('koa-session');const sessionConfig = { key: 'koa.sess', // Cookie 名称 maxAge: 86400000, // 有效期(毫秒) autoCommit: true, // 自动提交 overwrite: true, // 覆盖 httpOnly: true, // 仅 HTTP signed: true, // 签名 rolling: false, // 每次请求更新过期时间 renew: false, // 快过期时自动续期 secure: false, // 仅 HTTPS sameSite: null, // SameSite 策略};app.keys = ['your-secret-key']; // 必须设置用于签名app.use(session(sessionConfig, app));Session 使用:// 设置 Sessionapp.use(async (ctx) => { if (ctx.path === '/login') { ctx.session.user = { id: 1, name: 'John', role: 'admin' }; ctx.body = 'Logged in'; }});// 获取 Sessionapp.use(async (ctx) => { if (ctx.path === '/profile') { const user = ctx.session.user; if (user) { ctx.body = `Welcome ${user.name}`; } else { ctx.throw(401, 'Not logged in'); } }});// 删除 Sessionapp.use(async (ctx) => { if (ctx.path === '/logout') { ctx.session = null; ctx.body = 'Logged out'; }});3. Redis Session 存储:对于生产环境,建议使用 Redis 存储 Session。安装:npm install koa-session koa-redis配置 Redis Session:const session = require('koa-session');const RedisStore = require('koa-redis');const redisStore = RedisStore({ host: 'localhost', port: 6379, password: 'your-password', db: 0});const sessionConfig = { store: redisStore, key: 'koa.sess', maxAge: 86400000, httpOnly: true, signed: true};app.keys = ['your-secret-key'];app.use(session(sessionConfig, app));4. 认证中间件示例:// 认证中间件async function authMiddleware(ctx, next) { if (!ctx.session.user) { ctx.throw(401, 'Unauthorized'); } await next();}// 使用认证中间件router.get('/protected', authMiddleware, async (ctx) => { ctx.body = `Welcome ${ctx.session.user.name}`;});5. JWT Token 认证:使用 jsonwebtoken 和 koa-jwt 实现 JWT 认证。安装:npm install jsonwebtoken koa-jwt生成 Token:const jwt = require('jsonwebtoken');app.use(async (ctx) => { if (ctx.path === '/login') { const { username, password } = ctx.request.body; // 验证用户 const user = await authenticateUser(username, password); // 生成 Token const token = jwt.sign( { id: user.id, name: user.name }, 'your-secret-key', { expiresIn: '24h' } ); ctx.body = { token }; }});验证 Token:const jwt = require('koa-jwt');app.use(jwt({ secret: 'your-secret-key'}).unless({ path: [/^\/public/, '/login', '/register']}));// 访问用户信息app.use(async (ctx) => { ctx.body = ctx.state.user;});6. 完整的认证流程示例:const Koa = require('koa');const Router = require('@koa/router');const session = require('koa-session');const jwt = require('jsonwebtoken');const koaJwt = require('koa-jwt');const app = new Koa();const router = new Router();// Session 配置app.keys = ['secret-key'];app.use(session({ key: 'koa.sess', maxAge: 86400000}, app));// JWT 中间件app.use(koaJwt({ secret: 'jwt-secret'}).unless({ path: [/^\/api\/auth/]}));// 登录路由router.post('/api/auth/login', async (ctx) => { const { username, password } = ctx.request.body; // 验证用户 const user = await User.findOne({ username }); if (!user || !await user.comparePassword(password)) { ctx.throw(401, 'Invalid credentials'); } // 设置 Session ctx.session.user = { id: user.id, name: user.name }; // 生成 JWT Token const token = jwt.sign( { id: user.id, name: user.name }, 'jwt-secret', { expiresIn: '24h' } ); ctx.body = { token, user: { id: user.id, name: user.name } };});// 受保护的路由router.get('/api/user/profile', async (ctx) => { ctx.body = ctx.state.user;});// 登出路由router.post('/api/auth/logout', async (ctx) => { ctx.session = null; ctx.body = { message: 'Logged out' };});app.use(router.routes());7. 安全最佳实践:Cookie 安全:始终设置 httpOnly: true 防止 XSS生产环境使用 secure: true 仅 HTTPS设置 sameSite: 'strict' 防止 CSRF使用签名 Cookie 防止篡改Session 安全:使用强随机密钥设置合理的过期时间生产环境使用 Redis 存储登出时清除 SessionJWT 安全:使用强密钥设置合理的过期时间使用 HTTPS 传输实现 Token 刷新机制其他安全措施:限制登录尝试次数实现密码强度验证记录认证日志定期更新密钥