JWT的基础与使用

JWT JSON Web Token 是一种用于在各方之间传输信息的紧凑、安全的方式,常用于身份验证和授权。它以令牌的形式将用户信息编码后传输,可以确保数据的完整性和安全性。

1.JWT的结构

JWT 是一个基于 JSON 的令牌,由三部分组成,通过点号 (.) 分隔:

header.payload.signature

每部分都是经过 Base64Url 编码的字符串,分别对应以下三个部分:

1)Header (头部)

头部包含令牌的元数据,通常包括令牌类型和签名算法。

例子:

|--------------------------------------------------|
| { "alg": "HS256", "typ": "JWT" } |

alg: 签名使用的算法(如 HMAC SHA256)。

typ: 声明令牌类型为 JWT。

2)Payload (有效载荷)

有效载荷包含用户的声明(claims),也就是实际传输的数据。它通常包含身份验证或授权所需的信息。

|-------------------------------------------------------------------------------------------------------|
| { "sub": "1234567890", "name": "John Doe", "admin": true, "iat": 1516239022 } |

常见的标准声明:

  • iss (issuer):签发者
  • sub (subject):面向的用户
  • aud (audience):接收的受众
  • exp (expiration):过期时间
  • iat (issued at):签发时间
  • nbf (not before):生效时间

自定义声明:可以根据需求添加任何信息。

3)Signature (签名)

签名用于验证令牌的真实性,并确保令牌在传输过程中没有被篡改。

签名的生成方式:

|--------------------------------------------------------------------------------|
| HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) |

签名使用头部中声明的算法和一个秘密密钥(secret key)生成。

2.JWT的工作流程

2.1.生成JWT

用户登录后,服务器生成一个包含用户身份信息的 JWT,使用密钥对其进行签名。

2.2.客户端存储JWT

生成的 JWT 会返回给客户端,客户端通常将其存储在浏览器的 localStoragesessionStorage 中,或者存储在 Cookie 中。

2.3.客户端请求时携带JWT

在后续的请求中,客户端将 JWT 附加在请求头的 Authorization 字段中:

|---------------------------------|
| Authorization: Bearer <token> |

2.4.服务器验证JWT

服务器接收到 JWT 后,会使用相同的密钥对签名进行验证,确保令牌的完整性和真实性。

如果 JWT 有效,服务器允许访问资源;如果令牌无效或过期,返回 401 未授权状态。

3.JWT的优势

1)无状态:JWT 是无状态的,所有信息都保存在令牌中,服务器不需要维护会话数据。

2)跨域支持:由于 JWT 不依赖于特定的存储机制,适合跨域认证。

3)紧凑性:JWT 的结构紧凑,便于在 URL、HTTP 请求头等地方传输。

4)灵活性:JWT 可以包含任意声明,支持灵活的身份和权限管理。

4.JWT的使用场景

1)身份认证:用户登录后生成 JWT,之后每次请求时验证 JWT 以实现认证。

2)授权:通过 JWT 传递用户权限信息,确保用户只能访问被授权的资源。

3)信息传递:JWT 可以安全地传输一些加密的信息。

5. JWT 的安全性注意事项

签名算法 :建议使用强大的签名算法(如 HS256RS256),避免使用不安全的算法。

HTTPS:JWT 中可能包含敏感信息,传输时必须使用 HTTPS 来防止令牌被截获。

令牌过期 :为 JWT 设置合理的过期时间(exp 声明),防止长期有效的令牌被滥用。

刷新令牌:使用短期有效的访问令牌和长期有效的刷新令牌(Refresh Token)机制,以便在访问令牌过期后请求新的令牌。

6.Java代码实现生成和验证JWT

6.1.添加Maven依赖

如果你使用 Maven 构建项目,首先在 pom.xml 中添加 JJWT 库的依赖:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> </dependency> |

6.2.生成和验证 JWT 的 Java 代码

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| package com.me.mengyu.auth.net.jwt; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.Claims; import io.jsonwebtoken.security.Keys; import javax.crypto.SecretKey; import java.util.Date; public class JwtExample { // 生成一个密钥,用于签名 private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256 ); // 创建 JWT public static String createJwt(String subject) { // 设置 JWT 过期时间 long expirationTime = 1000 * 60 * 60; // 1 小时 return Jwts.builder() .setSubject(subject) // 设置主题(可以是用户ID等信息) .setIssuer("your-app") // 设置发行者 .setIssuedAt(new Date()) // 设置签发时间 .setExpiration(new Date(System.currentTimeMillis() + expirationTime)) // 设置过期时间 .signWith(SECRET_KEY ) // 使用密钥签名 .compact(); // 生成 JWT } // 验证 JWT 并提取信息 public static void validateJwt(String token) { try { // 解析 JWT Claims claims = Jwts.parserBuilder() .setSigningKey(SECRET_KEY ) // 设置密钥 .build() .parseClaimsJws(token) // 验证令牌 .getBody(); // 输出从 JWT 中提取的信息 System.out .println("Subject: " + claims.getSubject()); System.out .println("Issuer: " + claims.getIssuer()); System.out .println("Expiration: " + claims.getExpiration()); } catch (Exception e) { System.out .println("Invalid JWT token: " + e.getMessage()); } } public static void main(String[] args) { // 创建 JWT String jwt = createJwt("1234567890"); // 这里的主题可以是用户的ID System.out .println("Generated JWT: " + jwt); // 验证 JWT validateJwt(jwt); } } |

代码说明:

1)createJwt****方法 :生成一个带有签名的 JWT,包含用户身份信息(subject),签发者(issuer),签发时间和过期时间。使用 HS256 算法和一个密钥签名。

  1. validateJwt****方法 :验证 JWT 是否有效,并从中提取 claims 信息(如 subjectissuerexpiration)。如果令牌无效(例如过期或签名不匹配),会抛出异常。

运行结果示例:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Generated JWT: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaXNzIjoieW91ci1hcHAiLCJpYXQiOjE3MjcwMTcyNDYsImV4cCI6MTcyNzAyMDg0Nn0.tNylO-O5Jbazd0QzR85X8OB7p1mDy0IGtyl97Ro0FYQ Subject: 1234567890 Issuer: your-app Expiration: Mon Sep 23 00:00:46 CST 2024 |

说明:

生成的 JWT :格式为 header.payload.signature,其中 payload 包含 sub(用户ID)、iss(发行者)等信息。

验证 :输出 SubjectIssuerExpiration,表明 JWT 验证成功并解析出了信息。

6.3.注意事项

1)密钥管理:在生产环境中,应该安全地管理密钥,避免泄露。

2)过期时间:务必设置合理的过期时间,防止长时间有效的令牌带来安全风险。

3)异常处理:应当详细处理验证失败的情况,比如过期令牌、签名错误等。

相关推荐
江城开朗的豌豆4 分钟前
Vue 3.0真香!用了半年后我来告诉你为什么这么爽
前端·javascript·vue.js
前端工作日常4 分钟前
我理解的 npm 作用域包
前端
小小小小宇4 分钟前
移动端软键盘弹出问题
前端
小小小小宇5 分钟前
前端常见浏览器兼容性问题
前端
小小小小宇7 小时前
前端并发控制管理
前端
小小小小宇8 小时前
前端SSE笔记
前端
小小小小宇8 小时前
前端 WebSocket 笔记
前端
小小小小宇9 小时前
前端visibilitychange事件
前端
Johny_Zhao9 小时前
基于CentOS Stream 8的物联网平台深度优化方案
linux·网络·网络安全·信息安全·云计算·shell·yum源·系统运维
小小小小宇9 小时前
前端Loader笔记
前端