这篇文章主要探讨 在带后台的 SPA 场景下,如何在浏览器上存储 API token?这里的 API token 指带有用户身份或者会话信息,需要在每次浏览器请求后台 API 时发过去的数据。不限制它的格式和用途,它可以是个 JWT,也可以是个 OAuth 的 access token。
浏览器中存储数据主要有两种方式,cookie 及 HTML5 Storage API(包含 localStorage 及 sessionStorage)。Cookie 虽然主要用于被服务端生成及读取,并不是提供给浏览器存放内容使用,但是它刚好适用于这个场景。这也意味着对于 HTML5 Storage,需要额外的编程实现去将它带给服务端(典型的场景是通过 Authorization
头),而 cookie 不需要。
按多个维度进行的对比如下:
因素 | Cookie | HTML Storage |
---|---|---|
受 XSS 影响? | 仅 HttpOnly 的不受影响 | 是 |
受 CSRF 影响? | 实现得当时不受影响 | 否,只有 同源 的 JS 代码才可访问 |
内容长度限制 | 4096 字节每 cookie | 5Mb 数据每域名 |
会话相关机制 | 有 | 没有,需额外编程实现 |
请求后台时自动带上? | 是 | 否,需额外编程实现;同时你也往往不想把整个 storage 上传,而是只传其中的部分 key |
会话相关机制包括:
- 会话是否应该在某个时间自动失效?比如用户登录 30 天后失效,需要重新登录
- 会话有效期是否随用户使用而延长?比如已登录的用户每次打开页面做操作时,都自动把会话有效期延长到当前时间的 30 天后
- 是否需要实现「记住我(remember me)」功能?虽然目前大部分服务默认是记住的
这些机制在 cookie 上都有成熟的实现;在 JWT 上虽然可以实现,但是框架支持程度不一,有可能需要额外的工作量。
总体来看 Cookie 看起来是实现成本比较低的方式。但是它需要有好的 防 CSRF 实现,特别是在目前(2020 年 4 月)SameSite
未普及的时候。
对于 HTML Storage 方式,如果你的前端框架做好了整合,使得实现成本不高时,感觉比 cookie 更加灵活和安全。
具体选择哪种方式,我觉得更看你使用的前后台技术栈(前台如 React、VueJS 等,后台如 Django、Lavavel 等)中框架和流行库的支持程度。