1、简介
JWT(JSON Web Tokens)是一种用于双方之间安全传输信息的简洁的、URL安全的令牌标准。
它基于JSON对象,并通过数字签名确保其完整性和真实性。
JWT因其小巧、自包含以及易于在客户端和服务器之间传输的特性而被广泛使用于身份验证和信息交换的场景中。
2、组成部分
JWT由三个部分组成,这三部分通过点(.
)分隔:
Header(头部):头部通常包含了两部分信息:
例如:
typ
:表示令牌的类型,对于JWT,这个值通常是JWT
。alg
:表示签名所使用的算法,如HMAC SHA256或RSA。
{ "alg": "HS256", "typ": "JWT"
}
Payload(负载):负载包含了声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。声明分为三种类型:
- 注册声明(Registered claims):这是一组预定义的声明,它们不是强制的,但是推荐使用,如
iss
(发行人)、exp
(过期时间)、sub
(主题)等。 - 公共声明(Public claims):这些可以由使用JWT的双方自由定义。
- 私有声明(Private claims):这些也是自定义的声明,但通常只在创建令牌的双方之间共享。
例如:
{ "sub": "1234567890", "name": "John Doe", "admin": true
}
Signature(签名):签名部分是对前两部分的签名,以防止数据被篡改。
签名需要使用编码后的Header和Payload,一个密钥,以及算法(在Header中指定)来生成。
例如,如果使用的算法是HS256,签名将通过以下方式生成:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
3、使用场景及优缺点
3.1使用场景
- 身份验证:一旦用户登录,服务器就可以生成一个JWT并将其返回给用户。之后,用户就可以在后续请求中附带这个JWT来验证身份。
- 信息交换:JWT可以被用于在双方之间安全地传输信息。由于JWT是自包含的,它可以包含所有必要的信息,并且可以通过签名来验证其完整性和真实性。
3.2优点
- 紧凑:由于使用了Base64编码,JWT非常紧凑,易于通过URL、POST参数或HTTP头部传输。
- 自包含:JWT包含了验证和所需的所有信息,因此服务器不需要存储关于会话的额外信息或频繁地查询数据库。
- 跨域:JWT可以跨多个域安全地传输。
3.3缺点
- 安全性:JWT默认是不加密的,除非使用JWE(JSON Web Encryption)进行加密。因此,敏感信息不应该放在JWT的Payload中。
- 注销和令牌撤销:由于JWT是无状态的,很难在令牌过期之前撤销它。常见的解决方案是使用JWT与服务器端的黑名单或白名单配合。
- 令牌大小:虽然JWT通常很紧凑,但如果包含大量的声明,它可能会变得相当大,这可能会影响性能。
4、工作流程
1. 生成JWT
当用户通过身份验证(如登录)后,服务器会执行以下步骤来生成JWT:
1、创建Header(头部):Header部分是一个JSON对象,包含了令牌的元数据信息,如使用的签名算法(alg)和令牌的类型(typ,通常为JWT)。例如:
{ "alg": "HS256", "typ": "JWT"
}
2、创建Payload(负载):Payload部分也是一个JSON对象,包含了实际需要传递的声明(claims)。这些声明可以是预定义的(如iss发行人、exp过期时间等),也可以是自定义的。Payload也经过Base64URL编码,形成JWT的第二部分。
3、生成Signature(签名):为了确保JWT的完整性和真实性,服务器会使用一个密钥(secret)和一个签名算法(在Header中指定)来对Header和Payload进行签名。签名的生成过程通常涉及将编码后的Header和Payload拼接起来,然后使用密钥和算法进行签名。签名部分也进行Base64URL编码,形成JWT的第三部分。
4、组合JWT:将编码后的Header、Payload和Signature用点(.)分隔组合成一个完整的JWT字符串。
2. 传输JWT
生成JWT后,服务器会将其发送给客户端(如Web浏览器、移动应用等)。客户端随后可以在后续请求中附带这个JWT,以便进行身份验证或信息交换。JWT通常通过HTTP请求的头部(如Authorization头)发送,格式为“Bearer <token>”。
3. 验证JWT
当客户端发送带有JWT的请求时,服务器会执行以下步骤来验证JWT:
-
解析JWT:服务器将JWT字符串按点(.)分隔成三个部分,并分别对它们进行Base64URL解码,以恢复出原始的Header、Payload和Signature。
-
验证签名:服务器使用相同的密钥和签名算法对解码后的Header和Payload进行签名,并将生成的签名与JWT中的签名进行比较。如果两者相同,则表明JWT在传输过程中未被篡改。
-
验证Payload中的声明:服务器会检查Payload中的声明,如过期时间(exp)、发行人(iss)等,以确保JWT的有效性和适用性。
-
处理请求:如果JWT验证成功,服务器将处理客户端的请求,并返回相应的响应。如果JWT无效(如已过期、签名不匹配等),服务器将拒绝处理请求,并可能返回错误消息。