用户登录后拿到的Token,应该怎么存?

4466次阅读 173人点赞 作者: WuBin 发布时间: 2025-09-24 11:05:28
扫码到手机查看

基本处理方法优劣

用户登录后拿到的 Token,前端应该怎么存?

这个问题看似简单,却能清晰地分辨出一个前端开发者对安全的理解深度。是存到localStoragesessionStorage?还是Cookie?又或者是内存里?不同的选择背后,是截然不同的安全考量。

选项一:Web Storage(localStorage/sessionStorage

// 登录成功后
const token = 'your_jwt_token_here';
localStorage.setItem('auth_token', token);

// 后续请求时带上
axios.interceptors.request.use((config) => {
  const token = localStorage.getItem('auth_token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

优点:

  • 简单易用:API 简单,上手快。
  • 永久存储localStorage):除非手动清除,否则一直存在。
  • 会话期存储sessionStorage):页面关闭即清除,更安全一点。

致命缺点:

  • 极易受到 XSS (跨站脚本攻击) 的攻击。这是最核心的问题。如果网站存在 XSS 漏洞,攻击者的恶意脚本可以轻易地读取到localStorage中的所有 Token,从而窃取用户身份。

结论:不推荐,尤其对于敏感应用。除非你的应用完全不存在 XSS 风险(但这几乎不可能),或者 Token 的安全级别要求不高。

选项二:Cookie

Cookie 是传统且常见的身份验证载体。

// 服务端设置 Cookie (HTTP Response Header)
Set-Cookie: auth_token=your_jwt_token_here; Path=/; HttpOnly; Secure

// 前端无需特殊处理,浏览器会自动在每次请求中携带

注意这里的两个关键属性:

  • HttpOnly这是对抗 XSS 的神器。设置了HttpOnly的 Cookie 无法通过 JavaScript 的document.cookieAPI 访问,这意味着即使发生 XSS,攻击者也无法窃取到 Token。
  • Secure:强制 Cookie 只能在 HTTPS 协议下被发送,防止在网络传输中被窃听。

优点:

  • 免疫 XSS(得益于HttpOnly):无法通过 JS 读取,安全性高。
  • 可控制生命周期:通过ExpiresMax-Age设置过期时间。
  • 自动管理:浏览器自动在同源请求中携带。

缺点:

  • 容易受到 CSRF (跨站请求伪造) 的攻击。因为浏览器会自动在请求中带上 Cookie,攻击者可以诱导用户点击一个链接,从而以用户的身份发起恶意请求。
  • 需要额外的 CSRF 防护措施,如使用 Anti-CSRF Token、验证 Origin/Referer Header 等。

结论:是一个可行的方案,但必须配套完善的 CSRF 防御机制。

内存(Memory)

将 Token 保存在 JavaScript 变量中。

let inMemoryToken = null;

// 登录成功后
const login = async () => {
  const response = await loginAPI(username, password);
  inMemoryToken = response.data.token; // 存到内存变量
};

// 请求拦截器中添加
axios.interceptors.request.use((config) => {
  if (inMemoryToken) {
    config.headers.Authorization = `Bearer ${inMemoryToken}`;
  }
  return config;
});

// 退出登录或页面刷新时,Token 消失

优点:

  • 安全性极高:由于 Token 只存在于当前页面的内存中,关闭页面或刷新页面后 Token 立即消失。XSS 攻击者很难通过一次性注入的脚本持续地窃取到 Token(除非攻击代码常驻内存)。

缺点:

  • 体验差:页面一旦刷新,Token 就没了,用户需要重新登录。这对于单页面应用 (SPA) 来说是致命的。

结论:适用于安全要求极高、不介意频繁登录的场景(如银行系统)。对于普通 Web 应用,体验不可接受。

终极方案:组合拳 + 架构思维

既然没有完美的银弹,现代前端的最佳实践通常是组合方案架构优化

实践一:Cookie(HttpOnly + Secure) + 防御 CSRF

这是最传统但依然非常稳健的方案。

  1. 后端在登录成功后,设置一个HttpOnlySecure的 Cookie 来存放 Token(可以是 JWT,也可以是 Session ID)。
  2. 前端基本不用操心 Token 的存储和携带问题,由浏览器自动完成。
  3. 后端必须部署完善的CSRF 防护策略,例如:
    • 从 Cookie 中读取 Token 或 Session ID 进行身份验证。
    • 同时,要求请求必须携带一个额外的(由后端生成并通过 API 返回给前端的)X-CSRF-TokenHeader,并与 Session 中存储的值进行比对。

实践二:Access Token + Refresh Token

这是目前 API 接口认证非常流行的方案,完美解决了内存存储体验差的问题。

  1. 登录:用户输入密码登录。
  2. 返回双 Token:服务端返回两个 Token:
    • access_token:短期有效(例如 2 小时),用于请求受保护的 API。
    • refresh_token:长期有效(例如 7 天),仅用于获取新的access_token,不应具备API访问权限。
  3. 存储策略
    • access_token存入内存。这样即使被 XSS 窃取,有效期也很短,风险可控。
    • refresh_token存入HttpOnlyCookie。因为它有效期长,必须严加保护。由于其本身不直接用于业务请求,即使遭遇 CSRF,攻击者也无法用它来做任何关键操作(只能用来换一个短期的access_token,而该access_token又会因为存在于内存而难以被攻击者获取)。
  4. 无感刷新:当access_token过期后,前端自动(通过refresh_token)调用刷新接口获取新的access_token,用户无感知。

这个方案在安全性和用户体验之间取得了绝佳的平衡,是当前众多大型应用的首选。

总结与建议

存储位置优点缺点适用场景
Web Storage简单易用极易被 XSS不推荐用于存敏感 Token
Cookie可防 XSS (HttpOnly)需防御 CSRF传统 Web 应用(需配 CSRF 防御)
内存安全性极高页面刷新即失效安全至上、不介意体验的场景
组合策略安全与体验的平衡架构稍复杂现代 Web 应用最佳实践

给你的最终建议:

  • 如果你在做的是一个简单的、内部使用的、对安全性要求不高的工具,用localStorage图个方便也无可厚非,但要清楚风险。
  • 如果你在做的是一个传统的、服务端渲染的多页应用,使用HttpOnlyCookie 并配套 CSRF 防护是标准做法。
  • 如果你在做的是一个现代化的 SPA(如 React/Vue 应用),强烈推荐研究并采用Access Token (内存) + Refresh Token (HttpOnlyCookie)的方案。

安全没有绝对,只有相对的权衡。理解每种方案的利弊,并根据你的实际业务场景做出最适合的选择,才是最重要的。

相关资料

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:Cookie,安全,token
推荐阅读
  • python基础-操作列表和迭代器

    python基础笔记-操作列表和迭代器的相关方法

    6649次阅读 160人点赞 发布时间: 2024-06-13 13:26:27 立即查看
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    11842次阅读 800人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    15200次阅读 626人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    15706次阅读 1252人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    18465次阅读 1483人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    16652次阅读 1343人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    32336次阅读 2538人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    28282次阅读 2184人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录