简介:本文深入解析Node.js+Koa框架下实现跨域(不同域名/端口)Cookie共享的技术方案,包含CORS配置、Cookie属性设置及安全实践,提供完整代码示例与部署建议。
在微服务架构和前后端分离开发中,跨域请求已成为常态。当API服务(如api.example.com:3000)与前端应用(如app.example.org:8080)存在域名或端口差异时,浏览器默认会阻止携带Cookie的跨域请求。这种安全机制虽然防止了CSRF攻击,但也给需要身份验证的API调用带来挑战。
Koa通过@koa/cors中间件实现跨域控制,需重点配置以下参数:
const Koa = require('koa');const cors = require('@koa/cors');const app = new Koa();app.use(cors({origin: function(ctx) {// 动态匹配允许的域名const allowedOrigins = ['https://app.example.org','http://localhost:8080'];const origin = ctx.request.header.origin;return allowedOrigins.includes(origin) ? origin : false;},credentials: true, // 关键配置:允许携带凭证allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],allowHeaders: ['Content-Type', 'Authorization'],exposeHeaders: ['Content-Length', 'X-Koa-Version'],maxAge: 86400 // 预检请求缓存时间(秒)}));
true才能传输Cookie仅配置CORS还不够,需同时设置Cookie的以下属性:
const session = require('koa-session');app.keys = ['your-secret-key'];app.use(session(app, {key: 'koa:sess',maxAge: 86400000, // 24小时overwrite: true,httpOnly: true, // 防止XSS攻击secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPSsameSite: 'none' // 关键配置:允许跨域发送}));// 设置响应Cookie示例ctx.cookies.set('auth_token', 'abc123', {domain: '.example.com', // 子域名共享(需谨慎)path: '/',httpOnly: true,secure: true,sameSite: 'none',maxAge: 3600000});
| 属性 | 可选值 | 作用说明 |
|---|---|---|
| sameSite | strict/lax/none | strict: 完全禁止跨域 lax: 部分允许 none: 必须配合secure使用 |
| secure | true/false | 仅HTTPS下传输,防止中间人攻击 |
| httpOnly | true/false | 禁止JS访问,防范XSS |
| domain | 字符串 | 指定可访问的域名(如.example.com允许所有子域) |
const Koa = require('koa');const Router = require('@koa/router');const cors = require('@koa/cors');const session = require('koa-session');const app = new Koa();const router = new Router();// 会话配置app.keys = ['your-32-byte-long-secret-key'];app.use(session(app, {sameSite: 'none',secure: true}));// CORS配置app.use(cors({origin: (ctx) => {const allowed = ['https://app.example.org', 'http://localhost:8080'];return allowed.includes(ctx.request.header.origin) ? ctx.request.header.origin : false;},credentials: true}));// 登录接口router.post('/login', async (ctx) => {ctx.session.user = { id: 1, name: 'test' };ctx.cookies.set('session_id', '12345', {sameSite: 'none',secure: true,httpOnly: true});ctx.body = { success: true };});// 受保护接口router.get('/profile', async (ctx) => {if (!ctx.session.user) {ctx.status = 401;return;}ctx.body = { user: ctx.session.user };});app.use(router.routes());app.listen(3000);
// 登录请求(携带凭证)async function login() {const response = await fetch('https://api.example.com:3000/login', {method: 'POST',credentials: 'include', // 必须设置headers: {'Content-Type': 'application/json'},body: JSON.stringify({ username: 'test', password: '123' })});return response.json();}// 获取用户信息async function getProfile() {const response = await fetch('https://api.example.com:3000/profile', {credentials: 'include' // 必须设置});return response.json();}
.example.com通配符,避免权限过度开放检查项:
credentials: truecredentials: 'include'sameSite属性是否为none且secure为true解决方案:
http://localhost和http://127.0.0.1ngrok等工具生成HTTPS开发域名配置示例:
ctx.cookies.set('shared_cookie', 'value', {domain: '.example.com', // 允许所有子域访问sameSite: 'lax', // 子域共享时推荐laxsecure: true});
maxAge减少OPTIONS请求| 方案 | 优点 | 缺点 |
|---|---|---|
| Cookie | 浏览器自动管理,API简单 | 跨域配置复杂,有安全限制 |
| LocalStorage | 无跨域限制,容量大 | 需手动传输,XSS风险高 |
| JWT | 无状态,适合分布式系统 | 撤销困难,体积较大 |
通过本文的配置方案,开发者可以在Node.js+Koa环境中安全地实现跨域Cookie共享,既保持会话连续性,又符合现代Web安全标准。实际部署时,建议结合具体业务场景进行安全加固和性能调优。