Koa 的 Cookie 和 Session 管理是构建 Web 应用的基础功能,Koa 核心提供了 Cookie 操作,而 Session 需要通过中间件实现。
1. Cookie 操作:
Koa 核心内置了 Cookie 功能,通过 ctx.cookies 对象进行操作。
设置 Cookie:
javascriptapp.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:
javascriptapp.use(async (ctx) => { const username = ctx.cookies.get('username'); ctx.body = `Hello ${username}`; });
删除 Cookie:
javascriptapp.use(async (ctx) => { ctx.cookies.set('username', null, { maxAge: 0, path: '/' }); ctx.body = 'Cookie deleted'; });
2. Session 管理:
使用 koa-session 中间件实现 Session 功能。
安装:
bashnpm install koa-session
基本配置:
javascriptconst 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 使用:
javascript// 设置 Session app.use(async (ctx) => { if (ctx.path === '/login') { ctx.session.user = { id: 1, name: 'John', role: 'admin' }; ctx.body = 'Logged in'; } }); // 获取 Session app.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'); } } }); // 删除 Session app.use(async (ctx) => { if (ctx.path === '/logout') { ctx.session = null; ctx.body = 'Logged out'; } });
3. Redis Session 存储:
对于生产环境,建议使用 Redis 存储 Session。
安装:
bashnpm install koa-session koa-redis
配置 Redis Session:
javascriptconst 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. 认证中间件示例:
javascript// 认证中间件 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 认证。
安装:
bashnpm install jsonwebtoken koa-jwt
生成 Token:
javascriptconst 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:
javascriptconst 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. 完整的认证流程示例:
javascriptconst 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 存储
- 登出时清除 Session
-
JWT 安全:
- 使用强密钥
- 设置合理的过期时间
- 使用 HTTPS 传输
- 实现 Token 刷新机制
-
其他安全措施:
- 限制登录尝试次数
- 实现密码强度验证
- 记录认证日志
- 定期更新密钥