使用 JWT 在 SPA 应用里代替 Session

前言:这是今天研究 JWT 的时候写的一篇博文,主要是妄想在编写 SPA 应用时使用 JWT 代替 Cookie/Session,在写作期间诱发了一些更多面性的思考,使得这个想法被自己证实是完全行不通的。本文只作为记录心路历程

# JWT 的日常使用及重点解决方案

JWT :Json Web Token 是被设计用来在 api 场景中取代 Cookie/Session 的存在,本文讲解
JWT 的基本使用和关键点处理方案

关于 JWT 的使用其实是有一些争论的,大部分认为在 api 场景下 JWT 可以被用来取代 Cookies/Session,小部分人认为,由于 JWT 的无状态性,客户端无法完全控制 JWT 的更新,删除功能,为实现这些功能会加大项目整体的复杂性,并且无状态性的 JWT 会变成 `低状态` 的 JWT ,这种纷争各有道理,其争论的根本是在于项目大小,在不复杂的项目里,使用 JWT 会在一定的程度上增加项目的复杂度,在复杂的项目里 JWT 是可以被用来取代 Cookie/Session 的

## 1.JWT 的简单使用

JWT 是使用 json 来代替 cookie,并通过加密来保证 JWT 的不可更改。一般情况下 JWT 是一段由 `.` 分割的三段字符,分别称为:Header(头部)、Payload(负载)、Signature(签名),组成如下样子:`header.payload.signature` 。

### 1.1 Header

Header 是一个 URL 安全的 base64 编码后的 Json ,该 Json 称之为 JWT 的元数据,有 `alg` 和`typ` 两个属性,`alg` 被用来储存签名方式(加密方式),`typ` 被用来储存这段令牌的格式,值为 `JWT`

### 1.2 Payload

Payload 被用来储存令牌的信息,和 Header 一样也是一个 base64 后的 Json ,没有规定必须的属性,一般会放 签发人、生效时间、签发时间 等信息。**注意:**这些信息不具有加密性,不要储存私密信息

### 1.3 Signatrue

Signature 是重要部分,他保证了前两段信息的可靠性,Signature 被用来存放 Header 和 Payload 的签名,服务端将会按照 Header 字段里 `alg`属性加密 Header 和 Payload 生成 Signature

将 Header、Payload、Signature 用 `.` 连接起来就是一个可靠的 JWT

此段粗略介绍了 JWT ,如果想在你的项目里使用 JWT,请去阅读阮一峰先生写的 [JSON Web Token 入门教程](http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html)

## 2.使用 JWT 时进行 续签及注销

### 2.1 续签

在使用 Session 时,我们对 Cookie 设置了生效时间来保证一段会话的时效性,在换成 JWT 之后,我们只能在 Payload 中设置 过期时间 来保证时效性,但 JWT 的过期是死的,我们怎么保证在用户活跃的情况下无痛刷新令牌呢,在使用 Session 时,我们每个请求都刷新 Cookie 的过期时间即可,但刷新 JWT 相当与重新签发一个 JWT,这样会产生许多不必要的内存消耗,所以在解决这个问题的时候,我们一般使用如下方案:

- 设置一个续签时间,在用户 JWT 过期且不超过续签时间的情况下重新签发

在写这篇博文时,我看到 [该文章](https://segmentfault.com/a/1190000013151506) 提及了该方法涉及到一个多并发的问题,如果在过期后同时有两个请求过来,服务端会重新签发两个 JWT 返回,**但这是一个完全可以忽略的事情**,因为多签发一张 JWT 所带来的问题只有一个可以小到忽略的性能消耗,安全性上,多张 JWT 和一张 JWT 的安全性是相同的

### 2.2 注销

在使用 Session 时,我们想要注销一个用户的会话,只需要删除在服务端储存的 Session 文件即可,而在使用 JWT 的时候,我们没有办法这样做,我问过一些人在使用 JWT 的时候使用怎么处理注销的逻辑,得到的答案大都类似:

> 简单,删除客户端的 token 就好了

但这是一个不安全的办法,注销登录这个功能,在实际使用中并不是只有更换登录这一个作用,在用户遇到不可预料的 xss 攻击时,攻击者会获取到用户的登录令牌,如果这时候被用户察觉,可以通过注销的手段,作废这一次会话,从而攻击者获取到的令牌也被作废,使用 JWT 最大的一个问题就是一旦签发在过期时间内一直有效,这在一定程度上增加了危险性,网上给出的大多数做法是黑名单政策:将注销的 JWT 存到 redis 里,但这种方法

# **Stop using JWT for sessions !!!**

标签: none