SPA 应用中 Token 存储方案设计及解决方法探讨

背景

随着前端技术的不断发展,单页面应用(SPA)已经成为了前端开发中的一种重要技术方向。SPA 应用相比传统的多页面应用能够提供更好的用户体验和性能优化,但是也带来了一些新的挑战。其中之一就是如何安全地存储用户的 Token,在之前的多页面应用中,为了保持用户状态,Token 通常是存储在 Cookie 中,但是在 SPA 应用中,由于前后端分离的架构,Cookie 的设计方案已经不能够满足对 Token 存储的要求。下面就让我们一起来探讨 SPA 应用中 Token 存储方案的设计及解决方法。

Token 存储方案设计

在设计 Token 存储方案前,我们需要考虑以下两个问题:

  1. Token 需要存储在哪里?
  2. 存储的 Token 如何安全地传输和保存?

存储的位置

通常情况下,Token 可以存在三个位置:

  1. 存储在浏览器的本地存储(LocalStorage 或者 SessionStorage)中

    这种方案是最简单的,也是最容易实现的,并且能够满足大多数情况下的需求。但是存在一些风险,例如可能会遭受 XSS 攻击,导致 Token 被盗取。因此,这种方案并不适用于一些高安全性要求的应用。

  2. 存在浏览器的内存中

    在这种方案下,Token 是存在浏览器的内存中的,因此只在当前会话中有效,一旦关闭浏览器,Token 就会被销毁。由于 Token 不会被存储在硬盘中,因此更加安全。但是这种方案也存在一些限制,例如刷新浏览器页面时,Token 就会丢失。

  3. 存储在 Cookie 中

    这种方案和多页面应用中的方案一样,但是需要注意的是,在 SPA 应用中,如果 Token 存储在 Cookie 中,需要将其设置为 HttpOnly,以防止 XSS 攻击。

安全的传输和保存

为了保证传输和保存的安全性,可以采用以下几种措施:

  1. 使用 HTTPS 协议

    通过使用 HTTPS 协议来加密传输数据,对于网络劫持和中间人攻击提供保护。

  2. 在每次请求中携带 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


纠错反馈