前端登录token到底应该存在哪?LocalStorage、SessionStorage还是Cookie?一篇说透!

大家好,我是大华! 前几天有个小伙伴问我:"我登录之后拿到了token,到底该往哪儿存?LocalStorageSessionStorage还是Cookie?为啥不同网站做法不一样?" 说实话,这个问题我也曾经纠结过好久!每次看到不同项目用不同的存储方式,我就想问:到底哪个是对的?

前言

为什么token存储这么重要?想象一下,你家的钥匙你会放哪儿?随身携带?藏在门垫下面?还是交给保安?放错了地方,小偷就可能进你家门!

token就是用户进入系统的钥匙,存错了地方,黑客就能冒充用户登录账号,后果不堪设想啊!


一、区别

1. LocalStorage

  • 永久存储(除非手动删)
  • 同源就能读(JS随便拿)
  • 刷新不丢,关浏览器也不丢
  • XSS攻击下,Token直接暴露
  • 需要手动添加到请求头

2. SessionStorage

  • 只在当前会话有效
  • 同源可读
  • 适合临时操作
  • 关了浏览器标签就没了
  • 同样有XSS风险
  • 需要手动管理
  • 可设置过期时间
  • 可设置HttpOnly(JS拿不到!)
  • 可设置Secure(只走HTTPS)
  • 可设置SameSite(防CSRF)
  • 自动随请求发送(比如发API时自动带Token)
  • 容量限制(4KB)
  • 每次请求都携带(可能浪费流量)

4. 内存存储(Memory)

  • 页面刷新就丢失
  • 完全前端控制,不持久化
  • 最快最安全,但生命周期最短
  • 页面刷新就丢失
  • 不适合持久化需求
  • 标签页关闭就没了

二、为什么大家都用LocalStorage?

我懂,很多前端的朋友第一反应:"用LocalStorage最方便啊!"

两行代码搞定:

js 复制代码
// 存
localStorage.setItem('token', res.token);

// 发请求时
axios.defaults.headers.common['Authorization'] = localStorage.getItem('token');

方便、简单是真的,但同时也会伴随着安全隐患。

案例1:XSS攻击,Token被偷

假设你网站有个评论区,用户输入没做转义:

html 复制代码
<script>
  fetch('/steal?token=' + localStorage.getItem('token'))
</script>

用户打开页面,这条JS一执行,你的Token就会被发送到黑客服务器上。 而如果 Token 在HttpOnly Cookie里,JS 读不到,XSS 攻击直接失效。


三、用Cookie就完美了吗?

不,Cookie也有坑。黑客诱导你访问一个恶意页面:

html 复制代码
<img src="https://yourbank.com/transfer?to=hacker&amount=100000" />

如果你的登录态在 Cookie 里,浏览器会自动带上 Cookie,请求就成功了!

用户没点确认,钱就没了。

解决方案

方案一:前后端分离 + JWT + LocalStorage(最常见)

这是目前绝大多数新项目采用的方式。

技术栈:

  • 前端:Vue3 + Vue CLI / Vite,部署在 Nginx / CDN
  • 后端:SpringBoot,提供 RESTful API
  • 通信:Axios + JWT(JSON Web Token)
  • Token存储localStorage或内存

部署方式:

bash 复制代码
用户浏览器
    ↓
Vue 前端(http://fe.yourcompany.com) ←→ SpringBoot 后端(http://api.yourcompany.com)

前端和后端完全独立部署,通过CORS跨域通信。

认证流程:

  1. 用户登录

  2. SpringBoot验证用户名密码,生成JWT

  3. 返回给前端:{ token: "xxxxxx" }

  4. 前端存入 localStorage

  5. 后续请求,前端手动加Header:

    js 复制代码
    axios.defaults.headers.common['Authorization'] = 'Bearer ' + token
  6. SpringBoot在拦截器中解析JWT,验证身份

优点:

  • 前后端完全解耦,各自独立开发、部署、扩展
  • 适合微服务、云原生架构
  • 开发简单,调试方便
  • 可配合Nginx做负载均衡、缓存

缺点:

  • XSS 风险高 :一旦有富文本漏洞,localStorage中的token可能被盗
  • 需要手动管理token(过期、刷新)
  • 跨域配置麻烦(CORS)

📌 适用场景:

  • 中后台管理系统
  • ToC产品(官网、商城)
  • 快速上线的MVP项目

这是目前最主流的方案,90% 的新项目都这么干。


方案二:前后端合并部署(传统做法,逐渐减少)

把Vue打包后的dist文件放到SpringBoot的 resources/static 目录下,由SpringBoot统一提供页面和 API。

目录结构:

css 复制代码
src/
 └── main/
     ├── java/        ← SpringBoot 代码
     └── resources/
         ├── static/  ← Vue 打包后的 css/js
         └── templates/ ← index.html(可选)

访问方式:

  • 页面:http://localhost:8080/
  • API:http://localhost:8080/api/xxx

优点:

  • 部署简单,一个 jar 包搞定
  • 没有跨域问题
  • 适合小型项目、内部系统

缺点:

  • 前后端耦合,不利于独立迭代
  • 静态资源由 Java 服务提供,性能不如 Nginx
  • 不适合高并发场景

📌 适用场景:

  • 内部工具、小项目
  • 学习 demo
  • 对性能要求不高的系统

这种方案在企业级项目中逐渐被淘汰,但在教学和小项目中依然常见。


方案三:双 Token 机制(高安全要求项目)

这是金融、银行、高权限系统中越来越流行的"专业做法"。

方案核心:

  • access_token:短期JWT,存前端内存,用于API认证
  • refresh_token:长期token,存HttpOnly Cookie,用于刷新access_token

流程:

  1. 登录成功
    • 后端:Set-Cookie: refresh_token=xxx; HttpOnly; Secure
    • 响应体:{ access_token: "yyy" }
  2. 前端:
    • access_token到内存
    • 请求时加 Authorization: Bearer yyy
  3. access_token过期后:
    • /refresh 接口
    • 浏览器自动带refresh_token Cookie
    • 拿到新access_token

优点:

  • XSS 攻不破(refresh_tokenJS 拿不到)
  • 即使access_token泄露,有效期短(5-15分钟)
  • 安全性极高

缺点:

  • 实现复杂
  • 需要后端配合
  • 刷新机制要处理好并发

📌 适用场景:

  • 银行、支付、高权限后台
  • 对安全要求极高的系统

SpringBoot使用Spring Security + Session,登录后Set-Cookie: JSESSIONID=xxx; HttpOnly

Vue 前端不需要管 token,浏览器自动带 Cookie。

优点:

  • 安全性高(防 XSS)
  • 后端可管理 session(如强制下线)
  • 适合内网系统

缺点:

  • 需要处理 CSRF
  • 不适合无状态、微服务架构
  • 跨域配置复杂

📌 适用场景:

  • 传统企业系统
  • 内网管理系统
  • 已有 Spring Security 架构的项目

总结:四种方案对比

方案 安全性 易用性 推荐度 适用场景
前后端分离 + JWT + LocalStorage ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐☆ 90% 的新项目
前后端合并部署 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ 小项目、学习
双 Token 机制 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ 高安全系统
Cookie + Session ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ 传统企业系统

最终建议

  1. 如果你是新手或者做小项目:用前后端分离 + JWT + localStorage,简单直接。

  2. 如果你做中后台或者ToC产品:同上,但必须做好 XSS 防护(输入过滤、CSP、DOMPurify)。

  3. 如果你做金融或者高权限系统:上双 Token 机制,安全第一。

  4. 如果你是传统企业或者内网系统:可以考虑Cookie + Session,但要配好 CSRF。


目前 Vue + SpringBoot 的标准就是:前后端分离 + JWT + LocalStorage。

虽然它有 XSS 风险,但凭借开发效率高、架构清晰、适合云原生等优势,已经成为主流。

安全问题不是靠"不用 localStorage"解决的,而是靠:

  • 严格的输入验证
  • CSP 策略
  • 定期安全审计
  • 使用Content-Security-Policy

技术选型,永远是安全、效率、成本的权衡。

公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《工作 5 年没碰过分布式锁,是我太菜还是公司太稳?网友:太真实了!》

《别再被 Stream.toMap() 劝退了!3 个真实避坑案例,建议收藏》

《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》

《终于找到 Axios 最优雅的封装方式了,再也不用写重复代码了》

相关推荐
Fortunate Chen3 小时前
类与对象(下)
java·javascript·jvm
ChangYan.4 小时前
直接下载源码但是执行npm run compile后报错
前端·npm·node.js
skywalk81634 小时前
在 FreeBSD 上可以使用的虚拟主机(Web‑Hosting)面板
前端·主机·webmin
ohyeah5 小时前
深入理解 React 中的 useRef:不只是获取 DOM 元素
前端·react.js
MoXinXueWEB5 小时前
前端页面获取不到url上参数值
前端
低保和光头哪个先来5 小时前
场景6:对浏览器内核的理解
开发语言·前端·javascript·vue.js·前端框架
想要一只奶牛猫5 小时前
Spring Web MVC(三)
前端·spring·mvc
奋飛5 小时前
微前端系列:核心概念、价值与应用场景
前端·微前端·micro·mfe·什么是微前端
ji_shuke6 小时前
canvas绘制拖拽箭头
开发语言·javascript·ecmascript
2501_946244786 小时前
Flutter & OpenHarmony OA系统设置页面组件开发指南
开发语言·javascript·flutter