背景
随着前端技术的不断发展,单页面应用(SPA)已经成为了前端开发中的一种重要技术方向。SPA 应用相比传统的多页面应用能够提供更好的用户体验和性能优化,但是也带来了一些新的挑战。其中之一就是如何安全地存储用户的 Token,在之前的多页面应用中,为了保持用户状态,Token 通常是存储在 Cookie 中,但是在 SPA 应用中,由于前后端分离的架构,Cookie 的设计方案已经不能够满足对 Token 存储的要求。下面就让我们一起来探讨 SPA 应用中 Token 存储方案的设计及解决方法。
Token 存储方案设计
在设计 Token 存储方案前,我们需要考虑以下两个问题:
- Token 需要存储在哪里?
- 存储的 Token 如何安全地传输和保存?
存储的位置
通常情况下,Token 可以存在三个位置:
存储在浏览器的本地存储(LocalStorage 或者 SessionStorage)中
这种方案是最简单的,也是最容易实现的,并且能够满足大多数情况下的需求。但是存在一些风险,例如可能会遭受 XSS 攻击,导致 Token 被盗取。因此,这种方案并不适用于一些高安全性要求的应用。
存在浏览器的内存中
在这种方案下,Token 是存在浏览器的内存中的,因此只在当前会话中有效,一旦关闭浏览器,Token 就会被销毁。由于 Token 不会被存储在硬盘中,因此更加安全。但是这种方案也存在一些限制,例如刷新浏览器页面时,Token 就会丢失。
存储在 Cookie 中
这种方案和多页面应用中的方案一样,但是需要注意的是,在 SPA 应用中,如果 Token 存储在 Cookie 中,需要将其设置为 HttpOnly,以防止 XSS 攻击。
安全的传输和保存
为了保证传输和保存的安全性,可以采用以下几种措施:
使用 HTTPS 协议
通过使用 HTTPS 协议来加密传输数据,对于网络劫持和中间人攻击提供保护。
在每次请求中携带 Token
Token 通常会在 HTTP 的请求头中发送给服务器,这样可以在每次调用 API 时,进行身份验证。
解决方法探讨
本文介绍了三种 Token 存储方式和在存储时所需的安全措施,但是在实际应用中,我们可能需要综合考虑各种因素选择最合适的方案。
结合多种方案进行 Token 存储
可以采用多种方案进行 Token 存储的方式,例如将 Token 存储在本地存储中,并在每次调用 API 时,将 Token 携带在请求头中。
// 存储 Token localStorage.setItem("token", "xxx"); // 获取 Token const token = localStorage.getItem("token"); // 发送请求 axios({ url: "/api", headers: { Authorization: `Bearer ${token}`, }, });
实现自动化 Token 刷新
Token 的有效期通常是有限的,在过期后需要重新获取。为了避免 Token 过期后对用户体验的影响,可以实现自动化 Token 刷新的功能。
// managementToken.js import { refreshToken } from "api/auth"; let token = localStorage.getItem("token"); let refreshToken = localStorage.getItem("refreshToken"); const refreshTokenWithDelay = async () => { const delay = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); await delay(1000 * 60 * 10); // 10 minutes const res = await refreshToken(refreshToken); localStorage.setItem("token", res.token); localStorage.setItem("refreshToken", res.refreshToken); token = res.token; refreshToken = res.refreshToken; refreshTokenWithDelay(); }; const startRefreshingToken = () => refreshTokenWithDelay(); export { startRefreshingToken, token };
// auth.js import axios from "axios"; import { token } from "managementToken"; const getAccessToken = () => `Bearer ${localStorage.getItem("token")}`; export const refreshToken = async (refreshToken) => { const res = await axios.post("/api/refresh", { refreshToken: refreshToken, token: token, }); return { token: res.data.token, refreshToken: res.data.refreshToken, }; };
总结
本文介绍了在 SPA 应用中 Token 存储方案的设计和解决方法,并提供了一些实际的实现方案。最后,我们需要注意,因为安全性的要求在不同的应用中也不同,因此在设计 Token 存储方案时,需要综合考虑各种因素,选择最合适的方案。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/659def9aadd4f0e0ff712dcf