一篇文章理解JWT(Json Web Tokens)

时间:2021-08-11 17:09:44

JWT(JSON Web Tokens)是一项RFC的标准,由RFC 7519定义,用于两个实体之间安全地传输用JSON表示的数据。在传输过程中,JWT表现为一个字符串,可以通过HTTP的参数或者Header传输,由三部分字符串用点号相连,格式如下:

header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQiLCJleHAiOjEzNzE3MjA5Mzl9.
azSoRzdIHPLTNL2OsJsoXB1qCeThVYeEba_YYt6ZSTw

在应用程序中,JWT主要由JSON格式的header,payload,签名算法及密钥等内容组成。具体我们将在下文描述。

JWT主要的使用场景有:

  • 认证:用户登录后,后续的交互使用JWT来验证
  • 信息交换:可用于传输用户信息等数据

一个典型的场景如下图所示:
一篇文章理解JWT(Json Web Tokens)

①首先用户通过用户名密码向认证服务器发起请求
②认证服务器核实用户身份之后,生成一个Token返回到客户端,这个生成过程如下:首先构造称为header的JSON对象:

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

这个JSON包含两个字段,typ表示Token的类型,一般情况下为JWT,alg表示签名算法,这里我们使用HMACSHA256算法。

接着是payload部分,认证服务器验证密码后找到用户的ID,将其放入payload,并且给定一个过期时间:

{
    "userId":"b08f86af-35da-48f2-8fab-cef3904660bd",
    "exp":1371720939 }

接着我们把header和payload分别使用base64urlEncode算法编码,然后用点号连接起来,并且使用私钥和HS256算法进行签名,伪代码如下:

private_key = "---...---"
header_code = base64urlEncode(header)
payload_code = base64urlEncode(payload)
data =header_code + "." + payload_code
signature = HMACSHA256(data,private_key)
jwt = data + "." + signature

通过以上的过程,认证服务器将jwt返回的客户端,格式如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQiLCJleHAiOjEzNzE3MjA5Mzl9.azSoRzdIHPLTNL2OsJsoXB1qCeThVYeEba_YYt6ZSTw

需要注意的是,JWT并没有加密,而只是进行编码和签名,没有解决安全性问题,https等基础设施依然必要。

③OK,客户端现在拿到JWT,可以使用认证服务器的公钥进行验证,拿到payload里面的数据,用于页面展示等。然后携带JWT想应用服务器请求API。
④API服务器拿到JWT后,同样使用认证服务器的公钥验证签名,判断用户是否经过认证,token是否还在有效期内等,同样可以拿到payload中的用户id,用于日志等数据存储。认证完成之后,将业务数据返回给客户端。

上述提到的payload部分,按照标准,主要用于三类声明:

  • Registered claims: 这些是预定义的字段,用于特定的目的,例如iss表示token发行者,exp表示过期时间等。
  • Public claims:这些是公共的声明,一般采用uri前缀等方式避免冲突,在IANA JSON Web Token注册中心统一注册
  • Private claims:应用开发者自行决定的声明,如上面的userId字段。

几乎每一种编程语言都有对JWT的支持库,如python的pyjwt,具体参考jwt.io

参考:
jwt.io对JWT的介绍:https://jtw.io/introduction
5个步骤理解JWT:https://medium.com/vandium-software/5-easy-steps-to-understanding-json-web-tokens-jwt-1164c0adfcec