JWT令牌相关面试试题(举例说明)

2024-06-23 22:05:00 浏览数 (3)

什么是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令牌,在其有效期内无法修改或撤销,除非使用复杂的黑名单机制来使令牌失效。
jwt

1 人点赞