JWT 是 JSON Web Token 的缩写,它是一种基于 JSON 的开放标准(RFC 7519),用于在网络应用程序之间安全地传输信息。以下是关于 JWT 的详细介绍:
一、JWT 结构详解
1.头部(Header)
头部通常由两部分组成:令牌的类型(即 JWT)和使用的签名算法,例如 HMAC SHA256 或者 RSA。以下是一个 JSON 格式的头部示例:
{
"alg": "HS256",
"typ": "JWT"
}
这个 JSON 对象会使用 Base64Url 编码,生成一个字符串作为 JWT 的第一部分。Base64Url 编码与普通的 Base64 编码类似,但它对 URL 更友好,会将+
替换为-
,/
替换为_
,并去掉末尾的=
。
2.载荷(Payload)
载荷部分包含声明(Claims),声明是关于实体(通常是用户)和其他数据的声明。声明分为三种类型:
①.注册声明:这些是一组预定义的声明,不是强制要求的,但推荐使用。常见的注册声明有:
iss
(Issuer):签发者,标识 JWT 的签发实体。sub
(Subject):主题,通常是用户的唯一标识。aud
(Audience):受众,标识 JWT 的接收方。exp
(Expiration Time):过期时间,指定 JWT 的过期时间戳,超过这个时间,JWT 将失效。nbf
(Not Before):生效时间,指定 JWT 开始生效的时间戳,在这个时间之前,JWT 不可用。iat
(Issued At):签发时间,指定 JWT 的签发时间戳。jti
(JWT ID):JWT 的唯一标识符,用于防止 JWT 被重复使用。
②.公开声明:这些是在同意使用的各方之间定义的声明,通常是为了传递用户的自定义信息,例如用户的角色、权限等。
③.私有声明:这些是在同意使用的各方之间定义的声明,用于在这些特定的各方之间共享信息。
以下是一个载荷的示例:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}
同样,这个 JSON 对象也会使用 Base64Url 编码,生成 JWT 的第二部分。
3.签名(Signature)
要创建签名部分,需要使用编码后的头部、编码后的载荷、一个密钥(secret)和头部中指定的签名算法。例如,如果使用的是 HMAC SHA256 算法,签名将按以下方式创建:
import hmac
import hashlib
import base64
header = '{"alg": "HS256", "typ": "JWT"}'
payload = '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022, "exp": 1516242622}'
secret = 'your-256-bit-secret'
# Base64Url编码头部和载荷
encoded_header = base64.urlsafe_b64encode(header.encode('utf-8')).rstrip(b'=').decode('utf-8')
encoded_payload = base64.urlsafe_b64encode(payload.encode('utf-8')).rstrip(b'=').decode('utf-8')
# 拼接编码后的头部和载荷
signing_input = f'{encoded_header}.{encoded_payload}'
# 创建签名
signature = hmac.new(secret.encode('utf-8'), signing_input.encode('utf-8'), hashlib.sha256).digest()
encoded_signature = base64.urlsafe_b64encode(signature).rstrip(b'=').decode('utf-8')
# 最终的JWT
jwt = f'{encoded_header}.{encoded_payload}.{encoded_signature}'
print(jwt)
签名用于验证消息在传输过程中没有被更改,并且在使用私钥签名的情况下,还可以验证 JWT 的发送者的身份。
二、JWT 工作流程
1.客户端登录
- 用户在客户端输入用户名和密码,客户端将这些信息发送到服务器进行身份验证。
- 服务器验证用户名和密码的正确性,如果验证通过,服务器会根据用户的信息生成一个 JWT。
2.服务器生成 JWT
- 服务器使用用户的信息(如用户 ID、角色等)作为载荷,选择合适的签名算法和密钥,生成 JWT。
- 服务器将生成的 JWT 返回给客户端。
3.客户端存储和使用 JWT
- 客户端接收到 JWT 后,通常会将其存储在本地,例如使用浏览器的
localStorage
或sessionStorage
。 - 在后续的请求中,客户端会将 JWT 包含在请求头中,通常使用
Authorization
头,格式为Bearer <JWT>
。
4.服务器验证 JWT
- 服务器接收到请求后,会从请求头中提取 JWT。
- 服务器使用相同的密钥和签名算法对 JWT 进行验证,检查签名是否有效、JWT 是否过期等。
- 如果验证通过,服务器会从载荷中获取用户的信息,根据这些信息授权用户访问相应的资源。
三、JWT 的优缺点
1.优点
- 无状态性:服务器不需要在会话中存储用户的状态信息,这使得服务器可以更容易地进行扩展,例如使用负载均衡器将请求分发到多个服务器上。
- 跨域支持:由于 JWT 是通过 HTTP 头传输的,它可以很容易地在不同的域之间使用,适合于前后端分离的应用程序。
- 安全性高:JWT 使用签名和加密技术来确保数据的完整性和安全性,防止数据被篡改和伪造。
- 可扩展性强:可以在载荷中添加自定义的声明,以满足不同的业务需求。
2.缺点
- 令牌体积较大:由于 JWT 包含了所有必要的信息,当载荷中的信息较多时,JWT 的体积会比较大,增加了网络传输的负担。
- 无法中途撤销:一旦 JWT 被签发,在其过期之前,服务器无法主动撤销它。如果需要实现撤销功能,需要额外的机制,例如使用黑名单。
- 安全风险:如果密钥泄露,攻击者可以伪造 JWT,从而获得用户的权限。因此,密钥的管理非常重要。
四、JWT 的应用场景
1.身份验证
在单页应用(SPA)、移动应用等场景中,JWT 常用于用户登录后的身份验证。用户登录成功后,服务器返回 JWT 给客户端,客户端在后续的请求中携带该令牌,服务器通过验证令牌来确定用户的身份和权限。
2.单点登录(SSO)
在多个相关的应用系统中,用户只需要在一个系统中登录一次,就可以访问其他相互信任的系统,而无需再次输入用户名和密码。JWT 可以作为在不同系统之间传递用户身份信息的载体,实现单点登录的功能。
3.API 授权
当应用程序需要调用其他第三方 API 时,可以使用 JWT 来进行授权。将包含授权信息的 JWT 发送给 API 服务器,API 服务器验证令牌的有效性后,允许应用程序访问相应的资源。