JWT 简介
什么是 JWT
JWT 是 JSON Web Token 的缩写,是为了在网络应用环境间传递声明而执行的一种基于 JSON
的开放标准((RFC 7519)。定义了一种简洁的,自包含的方法用于通信双方之间以 JSON
对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT 可以使用 HMAC
算法或者是 RSA
的公私秘钥对进行签名。
JWT请求流程
![1bd6f189008ac9b2510ba4db134e8d9b.png](https://i-blog.csdnimg.cn/blog_migrate/15b29cc8b579d508104d289a8cd5c759.png)
- 用户使用账号和密码发起 POST 请求;
- 服务器使用私钥创建一个 JWT;
- 服务器返回这个 JWT 给浏览器;
- 浏览器将该 JWT 串在请求头中像服务器发送请求;
- 服务器验证该 JWT;
- 返回响应的资源给浏览器。
JWT 的主要应用场景
身份认证在这种场景下,一旦用户完成了登录,在接下来的每个请求中包含 JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录(SSO)中比较广泛的使用了该技术。 信息交换在通信的双方之间使用 JWT 对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。
JWT 数据结构
JWT 是由三段信息构成的,将这三段信息文本用 .
连接一起就构成了 JWT 字符串。
JWT 的三个部分依次为头部:Header,负载:Payload 和签名:Signature。
![fe89474c5481e0a3dd0e8fa5d36b7273.png](https://i-blog.csdnimg.cn/blog_migrate/86e3b73cb65bf8e2c7da50f7f729f0c4.png)
Header
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
"alg": "HS256",
"typ": "JWT"
}
上面代码中,alg
属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为 JWT
。
最后,将上面的 JSON 对象使用 Base64URL 算法转成字符串。
Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的有效信息。有效信息包含三个部分:
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用) :
- iss (issuer):签发人
- exp (expiration time):过期时间,必须要大于签发时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号,JWT 的唯一身份标识,主要用来作为一次性
token
,从而回避重放攻击。
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密。
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为 base64
是对称解码的,意味着该部分信息可以归类为明文信息。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
Signature
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,就可以返回给用户。
Base64URL
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx
)。Base64 有三个字符 +
、 /
和 =
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成 -
,/
替换成 _
。这就是 Base64URL 算法。
JWT 的使用方式
客户端收到服务器返回的 JWT 之后需要在本地做保存。此后,客户端每次与服务器通信,都要带上这个 JWT。一般的的做法是放在 HTTP 请求的头信息 Authorization
字段里面。
Authorization: Bearer
这样每个请求中,服务端就可以在请求头中拿到 JWT 进行解析与认证。
JWT 的特性
JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
JWT 不加密的情况下,不能将秘密数据写入 JWT。
JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
基于 nimbus-jose-jwt 简单封装
nimbus-jose-jwt 是最受欢迎的 JWT 开源库,基于Apache 2.0开源协议,支持所有标准的签名(JWS)和加密(JWE)算法。nimbus-jose-jwt 支持使用对称加密(HMAC)和非对称加密(RSA)两种算法来生成和解析 JWT 令牌。
下面我们对 nimbus-jose-jwt 进行简单的封装,提供以下功能的支持:
- 支持使用 HMAC 和 RSA 算法生成和解析 JWT 令牌
- 支持私有信息直接作为 Payload,以及标准信息+私有信息作为 Payload。内置支持后者。
- 提供工具类及可扩展接口,方便自定义扩展开发。