JWT Token 介绍
可以在这里反解 JWT token https://jwt.io/
这里可以看阮一峰老师关于JWT 的介绍 https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
JWT(JSON Web Token)是一种用于在各方之间安全传输信息的基于JSON格式的令牌,通常用于身份验证和授权。JWT令牌的结构相对简单,易于传递,并且可以在任何网络通信协议中(如HTTP)使用。以下是对JWT的详细解释以及它的工作过程。
一、JWT 的结构
JWT 由三部分组成,每部分使用点号 (.
) 分隔:
- Header(头部)
- Payload(载荷)
- Signature(签名)
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. Header(头部)
头部通常由两部分信息组成:
- 声明类型:即令牌的类型,JWT。
- 加密算法:例如HMAC、SHA256、RSA等。
{
"alg": "HS256",
"typ": "JWT"
}
上面的头部使用了 HS256
(HMAC-SHA256)作为签名算法,并且声明这是一个JWT令牌。头部会被编码为Base64Url格式。
2. Payload(载荷)
Payload 是JWT的主体部分,包含需要传递的数据。这些数据称为声明(claims)。JWT声明有三类:
- 注册声明(Registered claims):如
iss
(发布者)、exp
(过期时间)、sub
(主题)、aud
(受众)。 - 公共声明(Public claims):由双方自行定义,常用于身份验证,比如用户名、用户ID等。
- 私有声明(Private claims):仅用于双方之间的信息交换,例如特定应用上下文下的自定义信息。
一个常见的Payload示例:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}
Payload同样被编码为Base64Url。
3. Signature(签名)
签名部分用于验证消息的真实性,防止数据在传输过程中被篡改。签名的生成过程如下:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)
签名部分确保令牌在传输中不会被伪造或篡改。
二、JWT 的工作流程
JWT的工作过程可以分为创建和验证两部分,以下是详细的工作步骤:
1. 用户登录并请求令牌
用户通过提交有效的凭据(如用户名和密码)向服务器发出登录请求。服务器验证这些凭据。
2. 服务器生成 JWT
如果用户的凭据正确,服务器会生成一个JWT令牌。令牌中通常会包含以下信息:
- 用户的身份信息(如用户ID)。
- 有效期(expiration time)。
- 其他相关信息(如用户角色等)。
服务器会通过头部、载荷和签名来构造JWT。创建后的JWT如下所示:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
生成后的JWT通过HTTP响应返回给用户(通常是在HTTP header中返回,或在响应体中返回)。
3. 用户请求受保护的资源
用户在后续的每次请求中,会将JWT放在请求头中,比如在Authorization
头中使用Bearer方案:
Authorization: Bearer <JWT Token>
4. 服务器验证 JWT
每次用户请求受保护资源时,服务器会收到JWT,并进行以下验证:
-
完整性检查:服务器通过重新计算签名并与收到的JWT的签名进行比较,确保JWT没有被篡改。它会使用服务器端的密钥来验证。
-
过期检查:服务器检查JWT的
exp
(过期时间)字段,确保令牌未过期。如果令牌过期,服务器将拒绝请求并要求用户重新认证。 -
权限验证:服务器检查JWT中的声明是否包含用户有权访问的资源。如果用户的权限不足,服务器会拒绝请求。
5. 成功访问受保护资源
如果JWT通过了所有的验证,服务器会允许用户访问受保护的资源,并返回所需的响应。
三、JWT 的优势
-
无状态性:JWT 是无状态的,服务器无需在本地存储会话数据,这减少了服务器的存储负担。
-
可扩展性:因为JWT是在客户端存储的,令牌中可以携带与用户相关的额外信息,如角色、权限等,便于进行身份验证和授权。
-
跨域认证:JWT 可以轻松用于跨域认证,因为它是以JSON格式的令牌,可以在多个不同的服务之间共享。
-
简洁和易传输:JWT令牌结构简单,且通过Base64编码,适合用于HTTP头中传递。并且令牌体积小,减少带宽占用。
四、JWT 的缺点
-
不可撤销性:由于JWT是无状态的,服务器生成后无法撤销已经发出的令牌。通常解决办法是通过设置较短的过期时间,并配合刷新令牌机制。
-
信息公开:JWT的Payload部分是Base64编码的,不是加密的。虽然第三方无法伪造令牌,但他们可以解码并查看载荷中的信息。因此,在JWT中不要包含敏感信息。
-
令牌过期问题:如果JWT没有及时过期,或没有撤销机制,那么一旦令牌泄露,攻击者可以一直使用这个令牌进行恶意操作。
五、典型的JWT使用场景
-
用户身份验证:最常见的场景是在单点登录(SSO)系统中,JWT 用于在多个系统之间共享用户身份验证状态。
-
OAuth 授权:OAuth 2.0 中,JWT 被用作访问令牌来授权用户访问API资源。
-
微服务架构:在微服务架构中,JWT 可以在不同的微服务之间传递用户身份信息,避免每个微服务都需要独立进行身份验证。
六、JWT 与其他认证方法的对比
-
基于会话的认证:传统的基于会话的认证通常需要在服务器端存储用户的会话信息,而JWT是无状态的,无需在服务器上保存用户状态。
-
OAuth:JWT 常用于OAuth中作为访问令牌,与OAuth的授权流程紧密结合。相比OAuth的复杂性,JWT本身更简洁。
七、总结
JWT(JSON Web Token)是一种基于JSON的轻量级令牌,用于在客户端和服务器之间安全传递信息。通过它的三部分结构(头部、载荷和签名),JWT确保数据的完整性和安全性。在现代Web开发中,JWT广泛用于身份验证和授权,特别是在微服务和跨域应用场景中。
JWT Token 的签名和验证(验证签名)的过程:
在 JWT 的签名过程中,secret_key
是用于生成并验证签名的一个密钥。具体来说,secret_key
是服务器端的一个私有密钥,它用于确保 JWT 的签名和数据的完整性,防止令牌被篡改。
1. secret_key 的作用
secret_key
是在签名算法(如 HMAC-SHA256)中使用的密钥。在 JWT 的签名部分,服务器会使用这个密钥来加密 JWT 的头部和载荷,并生成签名。具体过程如下:
- 服务器将 JWT 的头部和载荷通过 Base64Url 编码后拼接。
- 服务器使用预先定义的加密算法(如 HMAC-SHA256)和
secret_key
计算出该拼接字符串的签名。 - 最终生成的 JWT 是由三个部分构成:头部、载荷、签名。
只有拥有 secret_key
的服务器才能生成或验证这个签名。如果有人尝试篡改JWT的头部或载荷,签名就会不匹配,从而服务器能够检测到。
2. secret_key 是从哪里来的?
2.1 由服务器生成和管理
secret_key
通常是由服务器生成并管理的一个私密密钥,它不会向客户端或任何其他第三方公开。服务器通过这个密钥来保证 JWT 的安全性。不同的应用程序会根据安全需求和架构选择不同的方式生成和管理 secret_key
:
-
静态密钥:通常在配置文件或环境变量中硬编码或配置。比如,使用常量密钥用于简单应用场景。
-
动态密钥:为了增强安全性,一些应用会动态生成和轮换密钥。动态密钥可以通过加密服务(如 AWS Key Management Service (KMS))生成。
-
密钥管理服务:在大规模生产环境中,企业通常使用诸如 Amazon KMS、Google Cloud KMS 或者 HashiCorp Vault 等专门的密钥管理服务,确保密钥的安全存储和定期轮换。
2.2 如何选择和配置 secret_key
配置 secret_key
时,以下几点需要注意:
-
随机性和复杂性:
secret_key
应该是足够长且随机的字符串,以避免暴力破解。使用弱密码或易猜的密钥会降低JWT的安全性。 -
存储安全性:
secret_key
需要安全存储,通常通过环境变量或者安全配置文件进行管理,避免暴露在源代码中。 -
定期轮换:在敏感应用中,密钥应定期进行轮换,这可以避免某些攻击类型(如长期暴露的密钥被破解)。
2.3 多服务器环境下的 secret_key
在分布式系统或微服务架构中,通常有多个服务器实例共同服务于请求。在这种情况下,所有的服务器实例需要共享同一个 secret_key
,这样任意一台服务器生成的 JWT 令牌都可以被其他服务器验证。
为了解决这个问题,通常有以下几种方式:
-
共享配置:所有的服务器实例都通过共享配置文件或者环境变量获取相同的
secret_key
。 -
集中管理密钥服务:使用密钥管理服务来为所有服务器提供统一的密钥服务,确保所有实例能够获得相同的密钥。
3. 如何验证 JWT 签名
当服务器收到带有 JWT 的请求时,会使用相同的 secret_key
来验证签名。验证过程如下:
- 服务器从JWT中分离出头部和载荷,并重新计算它们的签名。
- 使用服务器存储的
secret_key
和相同的加密算法(如 HMAC-SHA256),重新计算JWT的签名。 - 将计算出的签名与收到的JWT中的签名进行比较。如果签名匹配,则证明JWT没有被篡改。
4. JWT 的签名算法与密钥类型
JWT 支持多种不同的签名算法,每种算法对密钥有不同的要求:
-
对称加密算法(如 HMAC-SHA256):客户端和服务器共享同一个
secret_key
,它既用于生成签名,也用于验证签名。HMAC-SHA256 是 JWT 中常见的一种对称签名算法。 -
非对称加密算法(如 RSA 或 ECDSA):这类算法使用一对密钥(公钥和私钥)。服务器使用私钥签名,客户端或服务器可以使用公钥验证签名。这种方式更适合于分布式系统,因为客户端不需要知道服务器的私钥。
对于非对称加密,服务器生成JWT时使用的是私钥,而验证JWT时,客户端或其他服务使用服务器的公钥。
5. 示例:生成和验证 JWT 签名
生成 JWT 签名(以 HMAC-SHA256 为例):
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class JWTExample {
public static void main(String[] args) throws Exception {
// Header 和 Payload
String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
String payload = "{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}";
// Base64Url 编码
String encodedHeader = Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes());
String encodedPayload = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.getBytes());
// secret_key 用于签名
String secretKey = "your-secret-key";
// HMAC-SHA256 签名
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
hmacSHA256.init(secretKeySpec);
// 签名生成
String data = encodedHeader + "." + encodedPayload;
byte[] signatureBytes = hmacSHA256.doFinal(data.getBytes());
String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes);
// 最终的 JWT
String jwt = encodedHeader + "." + encodedPayload + "." + signature;
System.out.println("JWT: " + jwt);
}
}
验证 JWT 签名:
验证签名时,服务器使用同样的 secret_key
和 HMAC-SHA256 算法,计算JWT的头部和载荷部分的签名,并与接收到的签名进行比较。
6. 总结
secret_key
是JWT生成和验证中至关重要的安全要素。在使用对称加密算法(如HMAC-SHA256)时,secret_key
是用于生成和验证签名的密钥,确保JWT数据的完整性。它通常由服务器生成和安全管理,并且不会公开给客户端。通过使用强密码策略和安全管理机制,可以确保 secret_key
不被暴露,从而保证JWT的安全性。