核心原理
HTTP 是无状态协议;想要关闭浏览器再打开依然登录,核心是把身份凭证持久保存在浏览器本地,不能用 sessionStorage(关浏览器就清空)。
主流两套方案:持久Cookie(推荐,传统服务端Session)、Token + localStorage(前后端分离)
区分重点:
- session cookie(无过期时间):浏览器关闭直接删掉 → 下次打开需要重登
- persistent cookie(设置 Max-Age / Expires):写入本地文件,关浏览器不消失 → 实现记住登录
- sessionStorage:关闭浏览器清空,只保当前会话 ❌ 不能用
- localStorage:持久化存储,关闭浏览器还在 ✅ 适合存token
方案一:Session + 持久Cookie(传统方案,更安全)
流程:
- 用户提交账号密码登录,后端校验成功,在 Redis/数据库 创建一条会话,生成唯一
sessionId - 返回响应头
Set-Cookie,带上sessionId,设置 Max-Age(比如7天)、HttpOnly、Secure、SameSite
Set-Cookie: SESSION_ID=abc123xyz; Max-Age=604800; HttpOnly; Secure; SameSite=Lax; Path=/
- 浏览器把这个cookie持久化保存;关闭浏览器再打开网站,每次请求自动带上这个Cookie
- 后端拿到
SESSION_ID,去Redis查询会话是否有效,有效则保持登录;过期则跳转登录页 - 用户点击退出登录:后端删除Redis里session,同时下发指令清除Cookie
✅ 优点:凭证HttpOnly,JS拿不到,防XSS;登录状态后端可控,可以随时踢人下线
❌ 缺点:集群环境需要共享Session存储(Redis)
方案二:JWT Token + localStorage(前后端分离常用)
流程:
- 登录成功后端签发JWT token(包含用户信息、过期时间)返回前端
- 前端存入
localStorage
// 登录成功保存
localStorage.setItem('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...')
// 页面加载时读取
const token = localStorage.getItem('token')
if(token) {
// 请求头带上 Authorization: Bearer ${token},后端校验
}
// 登出
localStorage.removeItem('token')- 关闭浏览器再打开,localStorage数据还在;页面初始化读取token,请求后端校验有效性
补充:也会搭配 refreshToken 实现无感续期
✅ 优点:不需要服务器存会话,天然适合分布式、微服务
❌ 缺点:localStorage可以被JS读取,容易XSS窃取;JWT签发后,后端无法主动失效(除非维护黑名单)
安全优化:refreshToken放HttpOnly持久Cookie,accessToken放内存,不要长期放localStorage
方案对比速览
| 方式 | 关闭浏览器 | 安全 | 适用场景 |
|---|---|---|---|
| 会话Cookie(无Max-Age) | 失效,重登 | 高 | 银行、内网等高敏感,不希望记住登录 |
| 持久Cookie + SessionId | 保留登录 | 高 | 绝大多数网站“记住我”勾选框方案 |
| localStorage存Token | 保留登录 | 较低,XSS风险 | SPA前后端分离项目 |
| sessionStorage存Token | 关闭浏览器清空 | 中等 | 仅刷新页面保持登录 |
安全必加配置(Cookie方案)
HttpOnly:禁止JS读取Cookie,防御XSS窃取凭证Secure:仅HTTPS环境才发送CookieSameSite=Lax/Strict:防御CSRF攻击Max-Age:设置合理有效期(7天、30天),不要永久
常见坑
- 浏览器设置:开启“关闭浏览器自动清除Cookie”、无痕模式,持久Cookie也会失效
- Safari隐私策略:默认会做Cookie时效缩减(ITP),持久cookie可能提前失效
- 只把用户信息存在前端存储,不做后端校验:伪造本地存储就能冒充登录,绝对不可行
- 不要把账号密码直接存在Cookie/localStorage,只能存凭证(sessionId/token)
最简业务流程(记住我复选框)
登录页加【记住我】:
- ✅勾选:下发持久Cookie(带Max-Age)
- ☐不勾选:下发会话Cookie(无过期,关闭浏览器失效)
这就是大部分网站记住登录的实现方式。
如果你需要,我可以给你一套可直接跑的后端示例(Node/Java)或者前端鉴权路由守卫代码。