什么是 JWT ?

  jwt 是一个通过 json-web-token 规范 实现的 token 实例。
一个 jwt 实际上就是一个字符串。用户请求时在请求头或者 URI 附带 jwt ,server 端就能通过解密 jwt 的方式获取用户信息,免去了用户登录操作,简化了流程。因此使用 jwt 来进行用户授权认证是非常轻量和 restful 的。


JWT 的组成

jwt 由三个部分组成,分别是 头部(header), 签名(signature), 载荷(Payload),每个部分都是一个 json 对象。将三个 json 对象分别 encode 之后用 ‘.’ 连接起来就是一个 jwt 。

头部 (Header)

jwt 头部用来描述关于该 jwt 最基本的信息,例如 token 类型,签名所用的算法等等。

1
2
3
4
{
"typ": "JWT",
"alg": "HS256"
}

上面的例子中 typ 表示此 token 是 jwt ,alg 表示签名所用的算法是 HS256 。对 header 进行了 base64 编码之后就变成了 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷 (payload)

payload 供开发者存放有效信息。有效信息通常包括三个部分。

  1. JWT 标准中注册的声明
  2. 公共的声明
  3. 私有的声明

  • JWT 标准中注册的声明(建议但不强制使用):
    • iss: jwt签发者
    • sub: jwt所面向的用户
    • aud: 接收jwt的一方
    • exp: jwt的过期时间,这个过期时间必须要大于签发时间
    • nbf: 定义在什么时间之前,该jwt都是不可用的.
    • iat: jwt的签发时间
    • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • 公共的声明
    公共的声明可以添加任何信息,一般添加业务逻辑相关的必要信息,比如说用户信息,APP 信息等等,但是不建议添加敏感信息。

  • 私有的声明是提供者和消费者共同定义的声明,同样不建议存放敏感信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    "exp": 1488258366,
    "iat": 1487048766,
    "nbf": 1487048766,
    "identity": {
    "uid": "5809da9aa9ffb0431c152bd5",
    "email": "somebody@mail.com",
    "name": "somebody",
    "joindate": "2016-10-21 09:08"
    }
    }

    上面的例子中, exp 表示 jwt 过期时间是1488258366,iat 表示 jwt 签发时间是 1487048766,nbf 表示定义在 jwt 启用时间 为 1487048766 , identity 则是一个公共的声明,包含了部分用户信息。base64 之后得到了 jwt 的第二部分 eyJpZGVudGl0eSI6eyJqb2luZGF0ZSI6IjIwMTYtMTAtMjEgMDk6MDgiLCJ1aWQiOiI1ODA5ZGE5YWE5ZmZiMDQzMWMxNTJiZDUiLCJuYW1lIjoic29tZWJvZHkiLCJlbWFpbCI6InNvbWVib2R5QG1haWwuY29tIn0sImlhdCI6MTQ4NzA0ODc2NiwibmJmIjoxNDg3MDQ4NzY2LCJleHAiOjE0ODgyNTgzNjZ9

签名 (signature)

signature 由三个部分组成:

  1. header (base64 后的)
  2. payload (base64后的)
  3. secret

将前面编码的到的两个部分用 . 连接之后得到了: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6eyJqb2luZGF0ZSI6IjIwMTYtMTAtMjEgMDk6MDgiLCJ1aWQiOiI1ODA5ZGE5YWE5ZmZiMDQzMWMxNTJiZDUiLCJuYW1lIjoic29tZWJvZHkiLCJlbWFpbCI6InNvbWVib2R5QG1haWwuY29tIn0sImlhdCI6MTQ4NzA0ODc2NiwibmJmIjoxNDg3MDQ4NzY2LCJleHAiOjE0ODgyNTgzNjZ9
最后,我们将上面拼接完的字符串用 header 中 alg 所指定的算法 HS256 进行 salt 加密,加密的时候还需要提供一个密钥 secret 作为 salt .然后就构成了 jwt 的第三部分。

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

假定 secret 为 example_key 完整的 jwt 如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6eyJqb2luZGF0ZSI6IjIwMTYtMTAtMjEgMDk6MDgiLCJ1aWQiOiI1ODA5ZGE5YWE5ZmZiMDQzMWMxNTJiZDUiLCJuYW1lIjoic29tZWJvZHkiLCJlbWFpbCI6InNvbWVib2R5QG1haWwuY29tIn0sImlhdCI6MTQ4NzA0ODc2NiwibmJmIjoxNDg3MDQ4NzY2LCJleHAiOjE0ODgyNTgzNjZ9.hZRqFONsQcm6LH0Qv85tFgj3mWDYeUCEiTShZdkKhWc


相关链接


一些补充

签名的目的

signature 部分中 salt 加密的过程,实际上是对头部以及载荷内容进行签名。如果 server 端对 jwt 的 header 和 payload 再次以 header 中的 alg salt 之后发现,服务器端计算出来的 token 与接收到的 token 不一致,那么可以说明这个 token 是假的。

信息会暴露?

是的,信息确实会暴露。

因为 Header 和 payload 均采用了 base64 编码(相当于明文),所以 jwt 中是不适合放置敏感信息的。

JWT的适用场景

JWT适合用于在 Web 应用之间传递非敏感信息,帮助实现 Web 应用之间的业务逻辑以及用户授权,单点登录等等。


Enjoy :)