什么是token?

2,152 阅读4分钟

关于http的无状态

我们都知道http是一个无状态的协议,其无状态的特性主要体现在:从服务器的角度来看,服务器并不知道自己接收到的多条请求之间是否存在相互联系,因为在http协议中并没有做这样的规定。然后,这样的需求是很普遍的,比如说:有一条接口为/vip 还有一条接口为/login。我们的业务需要在/login接口中验证用户名和密码正确后,才可以访问/vip接口。因为刚才提到的无状态特性,导致我们首先不可以把/login接口和/vip接口建立起一个必然的联系。因此,我们需要一种方式能够建立起两条接口之间的联系。

如何让http存在状态

其实这个问题也很简单,基本思路就是在/login接口成功之后,服务端返回一个签名,然后/vip接口发起请求后如果能携带这个签名的话,那么我们就能知道/vip和之前的/login是有关系的。也可以根据签名的真伪去决定是否可以访问/vip接口。

现在生成签名基本上是两种方案分别是sessiontoken

使用session的方案

使用session的方案,就是当/login请求成功后,服务端生成一个签名,这个签名有三个特性

  1. 签名本身没有任何意义
  2. 签名应该是唯一的
  3. 服务端必须存储该签名(redis,内存,文件系统等等),方式任选。

服务器生成签名之后,一定要返回给浏览器端,浏览器端也需要对该签名做存储(可以选在存储在cookie,webStorage等),之后服务器再发起请求的时候需要携带该签名,然后服务端就可以根据该签名去建立两条接口之间的联系了。

通过流程图来看一下这种方式

使用session的方式会存在一些其他的问题,比如服务端存储的签名消失了,那么状态也就不存在了!思考一下一般在服务端哪些行为会让sessioin数据消失

使用token的方案

使用token方案的原理,同使用session方案的原理基本差不多!不同的地方就是服务端生成的签名不再是无意义的了,而是把一些有用的信息加密后得到的一份签名,也就是说该签名是存储有信息的。同时,该签名也不需要存储在服务端了。当然,该签名只能由特定的服务端进行解密。流程图如下:

JWT的规范

JWT是一个轻巧的规范,意思是json web token。这个规范规定了如何生成token; 一个JWT实际包含三部分:

  1. 头部
  2. 载荷
  3. 签名

载荷

载荷部分呢,其实就是一个JSON对象。可以在这里添加很多信息(希望在token中传递的信息都可以添加),除此之外呢,还有一些特定的字段

{
    "iss": "John Wu JWT",
    "iat": 1441593502,
    "exp": 1441594722,
    "aud": "www.example.com",
    "sub": "jrocket@example.com",
    "from_user": "B",
    "target_user": "A"
}

如下是特定的字段:

  • iss: 该JWT的签发者
  • sub: 该JWT所面向的用户
  • aud: 接收该JWT的一方
  • exp(expires): 什么时候过期,这里是一个Unix时间戳
  • iat(issued at): 在什么时候签发的

把上边提到的JSON对象进行base64编码,得到一串字符串,就是载荷,陈之为Payload

头部(header)

头部用于描述JWT最基本的信息,例如其类型以及签名所用的算法。

{
  "typ": "JWT",
  "alg": "HS256"
}

这里表名我们所用的算法是HS256算法

对该JSON对象也使用base64编码,得到的字符串就是头部(Header)。

签名

PayloadHeader.连接起来(Header在前)。得到一个新的字符串

最后,我们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,我们还需要提供一个密钥(secret)。那么就可以得到我们加密后的内容,这就是签名

完整的JWT

最后,我们把做如下拼接

`${Header}.${Payload}.${签名}`

这就是完整的JWT

node-jsonwebtoken

node-jsonwebtoken github地址

node-jsonwebtoken这个包已经完全实现了上述的JWT规范,使用该包就可以生成token字符串了

安装

npm install npm install jsonwebtoken

生成token

var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');

解析token

var jwt = require('jsonwebtoken');
var decoded = jwt.verify(token, 'shhhhh');