JWT,即 JSON Web Token,是一种跨域认证的解决方案,本文将详细介绍 JWT 的使用场景,原理和数据结构。
随着服务器集群或者跨域的服务导向架构的流行,对于传统的 Cookie Session 的认证方式,要求 session 数据在多个服务器中共享。一种解决方式是将 session 数据持久化,保存在数据库,但是这样会带来很大的工程量,同时如果持久层挂了,会单机失败。
另一种新的解决方式是,服务器不再保存 session 数据,而是将所有的数据都保存在客户端,每次请求的时候发回给服务器。JWT 便是这样一种跨域认证解决方案。
JWT 是一种基于JSON 的开放标准(RFC 7519),用作在网络应用环境间安全地传递信息。这种 token 被设计为紧凑而安全,特别适用于分布式站点的单点登录(SSO)场景。
使用场景
- 认证 这是 JWT 最常用的情景,作为跨域认证的凭证。
- 数据传输 因为 JWT 可以使用非对称加密方式生成签名,所以可以用来知道发送者是谁,同时验证信息是否被修改。
JWT 的原理
服务器对客户端进行认证后,生成一个 JSON 对象,即 JWT,发送给用户。
之后,每次用户给服务器发送请求时,都需要发回这个 JSON 对象。服务器通过这个 JSON 对象认证用户身份。
JWT 的数据结构
JWT 由三部分组成,中间使用 , 分隔,即 Header.Payload.Signature:
- 头部 Header
- 负载 Payload
- 签名 Signature
头部
头部是一个 JSON 对象,一般包括两部分,token 的类型,即 JWT,和签名的算法,比如(HMAC SHA256,RSA)。这一部分要使用 Base64Url 转化成字符串。
{ "alg": "HS256", "typ": "JWT" }
负载
负载也是一个 JSON 对象,用来放实际需要传输的数据,这一部分也要使用 Base64Url 转化成字符串。官方定义了7个字段,推荐使用但是不强制。
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
除此之外,还可以自己定义字段。
JWT 默认是不加密的,所以最好不要把秘密的信息放在这部分。
签名
签名部分是对强两个部分的签名,防止数据篡改。
- 指定一个密钥(只有服务器知道)
- 使用头部中
alg指定的签名算法产生签名。公式为:
总结
把使用 Base64Url 编码的头部和负载使用 . 连接,再加上计算出来的签名,就是完整的 JWT 啦。可以使用 jwt.io Debugger 感受一下 JWT 的生成和解码。
JWT 的使用方式
因为 token 是凭证,因此需要非常小心,防止安全问题。一般来说,按必要的最短时间保存令牌。
客户端接收到 JWT 之后,可以保存在 Cookie 中,也可以保存在 localStorage 中。
之后,每次客户端和服务器通信,都需要带上 JWT。有两种方式:
- 放在 Cookie 中,但是这样无法跨域。
- 放在 HTTP 请求头中的 Authorization字段,使用
Bearer模式Authorization: Bearer <token>。