session由服务端管理登录状态,token(如jwt)作为客户端携带的身份凭证,二者分层协作:前端路由守卫检查token存在性与时效性,服务端通过session做最终可信校验,实现双重守护。

JavaScript 中的 Session 和 Token 并不互斥,而是可以分层协作:Session 由服务端管理登录状态(如 Koa/Express 的 koa-session),Token(通常是 JWT)则作为客户端携带的身份凭证。二者配合实现「双重路由守护」,核心是让前端路由守卫既检查本地 Token 存在性,又依赖服务端 Session 做最终可信校验——不是简单叠加,而是分工明确、前后端协同。
Session 负责服务端可信状态,Token 负责客户端轻量传递
Session 是服务端维护的有状态会话(比如存在内存或 Redis 中),它天然具备防篡改、可销毁、可绑定 IP/设备等能力;Token(尤其是 JWT)则是无状态的签名凭证,适合跨域、轻量携带,但一旦签发就无法主动失效(除非额外加黑名单或短时效)。所以:
- 登录成功后,服务端创建 Session,并同时签发短期 Access Token + 长期 Refresh Token
- 前端把 Access Token 存 localStorage(便于跨页访问),Refresh Token 存 httpOnly Cookie(防 XSS 窃取)
- 每次请求带 Access Token;服务端收到后,先验证 JWT 签名和时效,再查 Session 是否有效(例如比对 session.id 是否匹配 token 中的 user_id + 登录指纹)
前端路由守卫只做快速拦截,不替代服务端鉴权
前端守卫(如 Vue Router 的 beforeEach 或 React 中的 Layout 组件)作用是提升体验、减少无效请求,但它不能也不该承担权限判定责任。正确做法是:
- 检查本地是否有未过期的 Access Token(用
jwt.decode()读 payload.exp,注意别依赖本地时间) - 若无 Token 或已过期,直接跳转登录页;若有,则放行到页面组件
- 页面组件内发起数据请求时,才真正触发服务端校验(此时 Session 和 Token 同时被验证)
- 如果服务端返回 401(Session 失效 / Token 被吊销),前端再统一处理登出逻辑
关键接口设计:登录、刷新、校验三者闭环
要让双重守护生效,后端必须提供三个基础能力:
- 登录接口:验证账号密码后,生成 Access Token(15–30 分钟)、Refresh Token(7 天),写入 Session 并将 Refresh Token 安全存入 httpOnly Cookie
- 刷新接口:接收 Refresh Token(自动从 Cookie 提取),校验其有效性及关联的 Session 状态,签发新 Access Token;失败则清空 Session + 删除 Refresh Token 记录
- 校验中间件:所有受保护路由前执行,先解析 Access Token,再查 Session 是否活跃、用户是否被踢出、权限是否变更
避免常见陷阱:不要把 Session 数据塞进 Token
有人会把 Session 中的 roles、last_login_ip 等字段直接写进 JWT payload,这看似省事,实则破坏无状态原则且带来安全隐患:
- Session 变更(如管理员禁用账号)后,JWT 不会自动失效,直到过期
- 敏感字段(如权限列表)暴露在前端可读的 Token 中,增加信息泄露风险
- 正确做法是 Token 只含最小身份标识(如
{ sub: "user_123", iat: 1721460000 }),具体权限、角色、状态全部由服务端实时查 Session 或数据库决定
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











