JWT 是什么?
JWT(JSON Web Token)是一种开放的标准,标准的编号是RFC7591。用于在不同实体之间安全地传输信息。它是基于 JSON 编码的令牌。
JWT 的组成
JWT由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- 头部(Header)包含了令牌的类型(typ)和所使用的签名算法(alg),通常使用 Base64 编码表示。示例如下:
{
"alg": "HS256",
"typ": "JWT"
}
- 载荷(Payload)是令牌的主要信息存储部分,包含了各种声明(claims),用于表示关于实体(用户、设备或其他主体)和其他补充数据的信息。载荷可以包含标准声明(例如:iss,sub,exp,nbf,iat,aud 等),也可以包含自定义声明。载荷同样会被进行 Base64 编码表示,并传输在令牌中。示例如下:
{
"sub": "myapp",
"name": "oscar",
"role": "admin"
}
- 签名(Signature)是使用密钥对头部和载荷进行签名的哈希值,以确保令牌不会被篡改。签名通常使用头部中指定的算法(例如:HMAC、RSA 等)和密钥来生成,并以字符串形式附加在令牌的末尾。签名验证可以用于验证令牌的完整性和真实性。
以Java语言产生JWT的过程来看,步骤如下:
- 产生头部的Base64编码串
String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
- 产生载体的Base64编码串
String payload = "{\"sub\":\"myapp\",\"name\":\"oscar\"}";
String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
- 使用点号
.
连接头部和载体之后, 再使用签名算法进行签名, 将签名后的内容附加在整个字符串的后面
Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String concatenated = encodedHeader + '.' + encodedPayload;
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] signature = sha256_HMAC.doFinal(concatenated.getBytes("utf-8"));
String compact = concatenated + '.' + Base64.getEncoder().encodeToString(signature);
产生后得到的完整字符串如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJteWFwcCIsIm5hbWUiOiJvc2NhciJ9.5z6NoiF7MR999wOPn2NU6HnyPODx66qm5yRT+n8pNHs=
通过 https://base64.us/ 解码之后获取的内容如下图:
从上面可以看出, JWT的令牌就是一串字符串。
JWT 的作用
JWT 适用于在网络请求中传输身份验证和授权信息,常用于构建无状态(stateless)的身份验证和访问控制机制。客户端在接收到令牌后,可以通过对令牌进行解码和验证来验证其有效性,并使用其中的信息进行授权和身份验证。
总结起来,JWT 是一种使用 JSON 编码的安全令牌,由头部、载荷和签名部分组成,可用于在实体之间传递信息和验证身份。它提供了一种简单、可扩展和自包含的机制,用于处理身份验证和授权相关的任务。
JWT也经常用于单点登录, 就是用户登录A系统之后,产生一个令牌, 之后访问其他系统都带上这个 Token,进而可以访问B,C,D等系统。
JWT优缺点
- 基于JSON,方便解析
- 可以在令牌中定义丰富的内容,易于扩展
- 通过非对称加密和数字签名,防篡改,安全性高
- 资源服务使用JWT就可以完成授权,不需要依赖授权服务器
缺点:
- JWT令牌较长, 占用较多的存储空间。
JWT的加密解密
JWT 的加密和解密通常涉及到以下三个步骤:
-
创建 JWT:
创建 JWT 需要准备三个部分:头部(Header)、载荷(Payload)和签名(Signature)。在创建 JWT 时,首先将头部和载荷进行 Base64 编码,并将这两个编码后的字符串用点号连接起来形成 JWT 的第一部分。接着,使用密钥和指定的签名算法对前面的字符串进行签名,生成签名字符串,并与前面的字符串用点号连接起来形成 JWT 的最终形式。 -
验证 JWT:
验证 JWT 的过程通常包括以下几个步骤:首先,对 JWT 中的头部和载荷部分进行Base64解码,提取其所包含的信息。接下来,用与创建 JWT 相同的算法和密钥,对头部和载荷部分计算签名。最后,将计算得出的签名字符串与 JWT 中的签名部分进行比较。如果两者相等,则表明 JWT 未被篡改过,可以被信任。 -
解码 JWT:
如果需要查看 JWT 中包含的数据,可以对 JWT 的第一部分进行 Base64 解码,以得到头部和载荷的信息。解码后的结果通常为 JSON 格式的字符串,可以通过相应的 JSON 解析库将其转换为对象。
需要注意的是,JWT 中的头部和载荷信息并没有加密,只进行了 Base64 编码。因此,这些信息可以被轻易地获取。为了保护数据的机密性,通常会使用加密算法加密载荷部分,即将其转换为 JWE(JSON Web Encryption)格式。JWE 提供了一种标准化的加密方式,以保护 JWT 中的敏感信息。加密 JWE 包括头部、密钥和加密后的密文等部分,需要使用相应的算法和密钥来进行解密。
总的来说,JWT 的加密和解密通常包括创建 JWT、验证 JWT 和解码 JWT 等步骤。其中,验证 JWT 可以用于验证 JWT 是否被篡改过,以保证 JWT 的完整性和可信度。而将载荷部分加密则可以保护 JWT 中的敏感信息,提高 JWT 的机密性。