通用会话控制方案

一、会话控制概念

  • 目的:在无状态的 HTTP 请求间识别/鉴权用户身份并维持登录状态。
  • 核心问题:谁保存"用户状态"?(服务器 / 客户端 / 第三方认证服务器),以及如何安全地在多请求间传递该凭证(Cookie / Authorization header)。

二、传统方案:Cookie + 服务端 Session

1) 流程

  1. 用户登录,后端验证凭证(用户名/密码)。
  2. 后端在服务器端创建 session(比如 sessionId 对应的对象存在 Redis / DB / 内存),并返回 Set-Cookie: sessionId=xxx; HttpOnly; Secure; SameSite=Lax; Path=/ 响应头部信息。
  3. 浏览器自动带上 Cookie(同源或按 CORS 配置带上 credentials: 'include'),后端根据 sessionId 在 session store 查到用户信息并授权。

2) 示例(Express + express-session + Redis)

后端:

JavaScript 复制代码
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET,
  name: 'sid',
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: true,      // 生产必须 https
    sameSite: 'lax',   // 或 'strict' / 'none'(配合跨域)
    maxAge: 24 * 3600 * 1000
  }
}));

前端(fetch):

JavaScript 复制代码
fetch('/api/profile', { credentials: 'include' })

3) 优点

  • 简单明确:后端完全控制会话(可以随时废弃/修改)。
  • 支持服务端会话失效(logout 立刻生效)。
  • 易于集成细粒度权限、会话统计与审计(存 Redis 的 session 可包含登录 IP、设备信息等)。

4) 缺点

  • 水平扩展需共享 session store(Redis)。
  • Session 存储和查询带来额外延迟与成本。
  • 跨域场景复杂:需要正确配置 Access-Control-Allow-Credentials、Set-Cookie 的 SameSite=None; Secure 等,避免安全问题。

三、JWT(JSON Web Token)方案概述

1) JWT 的基本思想(无状态 token)

  • 后端发放一个签名的 token(通常是 Access Token),包含用户 id、到期时间等。
  • 前端携带 token(通常放在 Authorization header 或者放入 HttpOnly cookie)向后端请求;后端不查 session store,而是直接验证 token 的签名与有效期,若通过则鉴权成功。

JWT 典型格式:header.payload.signature(Base64 编码)

JavaScript 复制代码
const jwt = require('jsonwebtoken');
const accessToken = jwt.sign({ uid: xxx }, process.env.JWT_SECRET, { expiresIn: '15m' });
const payload = jwt.verify(accessToken, process.env.JWT_SECRET);

2) 常见拓展

  • **短期 Access Token(如 5--15 分钟)**:放在内存或短寿命存储(不放 localStorage 更安全),用于 API 调用。
  • 长期 Refresh Token(如 14 天或更长)​:安全保存(​HttpOnly, Secure cookie),用于换取新的 Access Token。每次刷新都会发送新的 refresh token。服务端会保存 refresh token 的元数据(redis)。
  • Access Token 可放在 Authorization: Bearer <token>,或也可放在 HttpOnly cookie(同域 + credentials) 推荐将 Refresh Token 放 HttpOnly cookie,Access Token 放内存并通过 Authorization header 发送(减少 CSRF 风险)。

3) 优点

  • 无状态,后端不必保存 session(容易横向扩展,适合微服务 & 无状态后端),更适合移动端 SPA 等分布式鉴权。
  • Token 自包含(本身携带用户身份信息,后端只需验证 token 签名,就直接知道 token 是否有效以及用户信息,无需再查询数据库或者 session 存储),减少每次请求的 DB 查询。
  • 与 OAuth2 兼容,便于做 SSO 与第三方登录。

4) 缺点

  • 无法轻易撤销(access token 在有效期内一直可用,除非引入黑名单/撤销机制)。
  • 如果把 JWT 放在 localStorage(可被 JS 读取)会增加 XSS 风险;如果放 Cookie,则面临 CSRF 风险。

四、Cookie Session 与 JWT 的主要区别

表格 还在加载中,请等待加载完成后再尝试复制

五、安全策略

CSRF 防护(Cookie 自动带 credential 的情况下)

  • 优先:使用 SameSite=Lax 或 SameSite=Strict ​。
  • 对于必须 SameSite=None 的跨站场景,配合 **CSRF Token(双 submit cookie)**:
    • 后端在登录时设 Set-Cookie: CSRF-Token=xxx; HttpOnly=false; Secure(可被 JS 读取)
    • 前端每次请求在 header 中带 X-CSRF-Token: <value>,后端验证 header 与 cookie 值一致。
  • 或使用 Origin / Referer 检查(只允许来自可信域的请求)。

核心:CSRF 攻击者 ​可以发请求 ​,但 ​没法读 Cookie ​,无法把 token 放到 header 中,所以校验((req.cookies["CSRF-Token"] !== req.headers["X-CSRF-Token"]))。CSRF 攻击能发请求,但拿不到 cookie 内容 。

XSS 防护(避免 token 被窃取)

  • 对可执行 token 的存储避免使用 localStorage(HttpOnly cookie 防止 JS 读取)。

JWT 可撤销性策略

  • 短寿命 access token + refresh token (refresh token 存 HttpOnly cookie):
    • access token 过期快,可减少滥用窗口。
    • refresh token 在服务端有黑名单/DB 记录,必要时撤销(例如用户登出、密码变更)。
  • **token id(jti) + 存在服务端黑名单(Redis)**:在 logout / 强制下线时把 jti 写入黑名单并在验证时检查。黑名单可设置过期与分布式缓存。
相关推荐
三天不学习8 小时前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
发光小北8 小时前
四路can转WIFI在现场应用中有什么问题?
网络协议
xcs194059 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
天启HTTP9 小时前
爬虫防封核心原理:IP轮换机制与风控规避逻辑
linux·服务器·网络·爬虫·tcp/ip
明月_清风10 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
Csvn11 小时前
框架性能优化
前端
回眸&啤酒鸭12 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138413 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员13 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子13 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端