什么是JWT令牌
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间以json数据格式安全的传输信息。
JWT令牌的结构
JWT令牌由三个部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature),它们之间使用点(.)分隔。
一个JWT令牌的典型结构如下:
代码语言:javascript复制xxxxx.yyyyy.zzzzz
Header(头部): 头部通常由两部分组成:令牌类型(即 "JWT")和所使用的签名算法(如HMAC SHA256或RSA)。头部是一个JSON对象,使用Base64Url编码。
代码语言:javascript复制{
"alg": "HS256",
"typ": "JWT"
}
Payload(载荷): 携带一些自定义信息、默认信息等。载荷部分包含声明(claims),声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:注册声明(registered claims)、公共声明(public claims)和私有声明(private claims)。这个部分也是一个JSON对象,使用Base64Url编码。
代码语言:javascript复制{
"id": "1",
"name": "John",
"exp": 1516239022
}
Signature(签名): 签名部分是为了确保令牌不被篡改。它由编码后的头部、编码后的载荷和一个密钥通过指定签名算法计算而来。
正是因为jwt令牌数字签名部分的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。
JWT令牌签名的创建过程
假如采用HMAC SHA256算法,签名的完整创建过程如下所示:
代码语言:javascript复制HMACSHA256(
base64UrlEncode(header) "."
base64UrlEncode(payload),
secret
)
假设Header为:
代码语言:javascript复制{
"alg": "HS256",
"typ": "JWT"
}
编码后的Header为:
代码语言:javascript复制eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
假设Payload为:
代码语言:javascript复制{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
编码后的Payload为:
代码语言:javascript复制eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
生成签名:
代码语言:javascript复制HMACSHA256(
base64UrlEncode(header) "."
base64UrlEncode(payload),
secret
)
假设secret为:your-256-bit-secret
生成的签名(Base64Url):
代码语言:javascript复制TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
完整的 JWT:
代码语言:javascript复制eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWT令牌是为了解决什么问题
传统会话跟踪技术(同一次会话中多次请求之间的数据可以共享)是通过cookie和session,但这两者有许多缺点。
以用户验证这一实际场景举例,如果使用JWT令牌进行用户验证,服务器在用户成功登录后生成一个JWT令牌,并将其发送给客户端浏览器。客户端在后续的每个请求中都携带这个令牌,服务器通过验证这个令牌是否存在、令牌是否合法这两个方式来确认用户身份。JWT令牌的优点:
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器的存储压力(无需在服务器端存储)
JWT令牌的优缺点
- 优点:
- 支持PC端、移动端
- 解决集群环境下的认证问题
- 减轻服务器的存储压力(无需在服务器端存储)
- 缺点:需要自己实现(包括令牌的生成、令牌的传递、令牌的校验)
JWT令牌能否多服务器共享
因为JWT是无状态的,包含所有必要的信息,并且可以通过签名来验证其完整性,所以不同服务器只需知道签名密钥即可验证令牌、共享数据,而不需要共享会话状态,从而实现了多服务器的之间的共享。
JWT令牌多服务器共享的场景举例:
假设有一个负载均衡的应用,分布在多个服务器上,用于处理用户的请求。系统架构主要包含以下三个部分:
- 服务器1:用于处理用户登录请求,生成JWT令牌。
- 服务器2:用于处理用户的其他请求,验证JWT令牌。
- 负载均衡器:分配用户的请求到不同的服务器。
步骤1:用户通过HTTP POST请求,用于发送用户的登录信息到服务器,以进行身份验证。负载均衡器将请求分配到服务器1。
代码语言:javascript复制POST /login HTTP/1.1
Host: example.com
Content-Type: application/json
{
"username": "user1",
"password": "password123"
}
步骤2:服务器1验证用户凭证,如果有效,则生成一个JWT令牌,包含用户ID和其他信息,并使用服务器的签名密钥进行签名。以下代码声明令牌的主题为user1,令牌有效期为1个小时,使用HS512(HMAC SHA-512)算法和密钥“shared-secret-key”对JWT进行签名。
代码语言:javascript复制String jwtToken = Jwts.builder()
.setSubject("user1")
.setExpiration(new Date(System.currentTimeMillis() 3600000))
.signWith(SignatureAlgorithm.HS512, "shared-secret-key")
.compact();
步骤3:服务器1将JWT令牌的字符串形式token返回给客户端,客户端将这个令牌存储在本地存储或Cookie中。唠叨:客户端在后续的每次请求中,都需要在请求头header中将这个令牌携带到服务端,请求头的名称为 token ,值为登录时下发的JWT令牌,验证通过后才能放行处理请求。
代码语言:javascript复制
HTTP/1.1 200 OK
Content-Type: application/json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
步骤4:客户端请求一个受保护的资源,负载均衡器将请求分配到服务器2。服务器2接收到请求后,从HTTP请求头部提取名为token的JWT令牌,并使用共享的签名密钥"shared-secret-key"验证令牌。如果令牌签名验证成功且未过期,则处理请求并返回响应。
代码语言:javascript复制// 验证JWT令牌
Claims claims = Jwts.parser()
.setSigningKey("shared-secret-key")
.parseClaimsJws(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...)
.getBody();
String username = claims.getSubject();
步骤5:服务器2验证令牌成功后,处理请求并返回响应。
代码语言:javascript复制HTTP/1.1 200 OK
Content-Type: application/json
{
"message": "This is a protected resource."
}
Session和JWT有什么区别
1.数据存储方式
Session:
- 服务器端存储:会话数据存储在服务器端(例如内存、数据库或其他持久化存储)。服务器需要维护每个用户的会话状态。
- 客户端存储:客户端仅存储一个会话ID,通常保存在Cookie中,后续请求会携带此会话ID来查找服务器端存储的会话数据。
JWT:
- 客户端存储:JWT令牌自包含所有会话数据,存储在客户端本地(或cookie)。服务器无需存储会话状态,只需共享签名密钥即可验证JWT令牌。
- 无服务器存储:服务器不需要存储或管理会话数据,令牌中包含所有必要的信息(如用户身份和权限)。
2.扩展性
Session:
- 扩展性差:在分布式系统中,需要共享会话数据或使用集中式存储(如数据库或缓存服务器),增加了复杂性和性能瓶颈。
- 服务器负担重:随着用户数量增加,服务器需要管理更多的会话数据,可能会导致性能下降。
JWT:
- 扩展性好:由于JWT令牌是无状态的,服务器不需要存储会话数据,易于在分布式系统和微服务架构中扩展。
- 减少服务器负担:每个请求携带完整的JWT令牌,服务器只需验证令牌的签名和有效期,不需查找会话数据,提升了性能。
3.安全性
Session:
- 安全性高:会话数据存储在服务器端,不易被篡改。客户端只存储一个会话ID,攻击者难以伪造会话。
- 可控性强:服务器可以随时终止会话或修改会话数据,具有更高的控制权。例如,可以立即使某个会话失效。
JWT:
- 安全性问题:JWT令牌一旦泄露,攻击者可以伪装用户,直到令牌过期。
- 可控性弱:服务器一旦签发JWT令牌,在其有效期内无法修改或撤销,除非使用复杂的黑名单机制来使令牌失效。