JWT解决用户认证的问题,在用户登录的时候,客户端发起登录请求,服务端就可以返回一个JWT token
,客户端在之后的请求中都带上这个token(一般是放在请求头的 Authorization 字段中),服务端就能知道是哪个用户了,实现服务端无状态
。
一个JWT token
大概是长这样子的,是一个很长的字符串,分为3段,中间用.
分隔,每个部分都是经过base64编码过的,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
前两部分可以解码得出有效的json,最后一部分是通过一定算法作用在前两部分得出的签名
,
{"alg":"HS256","typ":"JWT"}.{"sub":"1234567890","name":"John Doe","iat":1516239022}.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
第一部分叫做 Header,Header 包含了 JWT 的一些元信息。
在 Header 中,alg
是必须指定的值,他表示 JWT 的签名方式,例子中 JWT 使用的是 HS256 进行签名,也就是使用 SHA-256 作为摘要算法。常见的选择还有 RS256,ES256 等等。总结一下:
HSXXX 或者说 HMAC:一种对称算法 (symmetric algorithm),也就是加密密钥和解密密钥是同一个。类似于我们创建 zip 文件时设定的密码,验证方需要知道和签名方同样的密钥,才能得到正确的验证结果。
RSXXX:使用 RSA 进行签名。RSA 是一种基于极大整数做因数分解的非对称算法 (asymmetric algorithm)。相比于对称算法的 HMAC 只有一对密钥,RSA 使用成对的公钥 (public key) 和私钥 (private key) 来进行签名和验证。大多数 HTTPS 中验证证书和加密传输数据使用的是 RSA 算法。
ESXXX:使用 椭圆曲线数字签名算法 (ECDSA) 进行签名。和 RSA 类似,它也是一种非对称算法。不过它是基于椭圆曲线的。ECDSA 最著名的使用场景是比特币的数字签名。
PSXXX: 和 RSXXX 类似使用 RSA 算法,但是使用 PSS 作为 padding 进行签名。作为对比,RSXXX 中使用的是 PKCS1-v1_5 的 padding。
除了 alg ,官方还定义了一些其他的 key ,这里就不详细讲了。
第二部分是 Payload Payload 里面存的是一些有意义的数据,上面例子中解码后的数据如下:
{"sub":"1234567890","name":"John Doe","iat":1516239022}
和 Header 类似, Payload 中也有一些预定义的 key ,我们称他们为 claim。常见的预定义的 key 包括:
除了官方字段,开发者也可以自定义私有字段,比如里面的 name 就是私有字段。
但是注意 Payload 是不加密的,不要把隐私信息放入 Payload 中。
最后一部分是签名(Signature),签名是对 Header 和 Payload 的原文进行 base64 编码,然后用.
连接,最后扔给签名算法进行签名,签名得到的算法再进行 base64 编码,就能得到签名了。
伪代码:
// 比如使用 RS256 签名:
let 签名数据: Data = RS256签名算法(Base64Url(string: Header).Base64Url(string: Payload), 私钥)
let 签名: String = Base64Url(data: 签名数据)
最后,再把三部分用.
连接起来,就是我们看到的 JWT 了。
JWTtoken一般有两个失效时间:
一个是token本身的失效时间,这个很好理解,就是过了这个时间token就失效了。
还有一个是token过期后,再次刷新的有效期,也就是token过期后,你还有一段时间可以重新刷新,服务端会返回一个新token。