JWT:结构、创建与验证
手动解码 JWT 结构,使用密钥创建签名令牌,并在不使用框架的情况下验证声明
JWT:结构、创建与验证 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
什么是 JWT?
JSON Web 令牌(JWT)是一种紧凑且适合 URL 的令牌格式,用于在参与方之间传输声明。JWT 会进行签名(也可以选择加密)。它是自包含的,验证声明时无需查询数据库。
JWT 结构:Header.Payload.Signature
JWT 由三个使用 Base64URL 编码的部分组成,部分之间用点分隔:header.payload.signature。标头指定算法。载荷包含声明。签名用于验证完整性。
// Example JWT:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 <- header
// .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0 <- payload
// .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c <- signature已解码的标头和载荷
使用 Base64URL 解码每个部分即可查看 JSON。载荷包含“声明”,常见声明包括:sub(主题)、iss(签发方)、exp(过期时间)和 iat(签发时间)。
// Header:
{ "alg": "HS256", "typ": "JWT" }
// Payload:
{ "sub": "user-42", "name": "Alice", "role": "ADMIN",
"iat": 1716000000, "exp": 1716003600 }手动创建 JWT(HS256)
构建标头和载荷 JSON,分别进行 Base64URL 编码,用点连接,然后对 header.payload 计算 HMAC-SHA256,并将结果作为签名追加。
String header = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
String payload = Base64.getUrlEncoder().withoutPadding()
.encodeToString("{\"sub\":\"user-42\",\"exp\":9999999999}".getBytes());
String sigInput = header + "." + payload;
byte[] sig = computeHmac(secretKey, sigInput);
String jwt = sigInput + "." + Base64.getUrlEncoder().withoutPadding().encodeToString(sig);手动验证 JWT
按点分割,解码标头和载荷,对 header.payload 重新计算 HMAC,将结果与签名比较,并检查 exp 是否晚于当前时间。
String[] parts = jwt.split("\\.");
String sigInput = parts[0] + "." + parts[1];
byte[] expectedSig = computeHmac(secretKey, sigInput);
byte[] actualSig = Base64.getUrlDecoder().decode(parts[2]);
if (!MessageDigest.isEqual(expectedSig, actualSig)) throw new SecurityException("Invalid signature");
// Decode payload and check exp:
String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]));
// parse JSON and check exp > now使用 java-jwt 库(Auth0)
com.auth0:java-jwt 库通过流式 API 简化了 JWT 的创建和验证。
// Create:
Algorithm alg = Algorithm.HMAC256(secretKey);
String token = JWT.create()
.withSubject("user-42")
.withClaim("role", "ADMIN")
.withExpiresAt(Instant.now().plusSeconds(3600))
.sign(alg);
// Verify:
JWTVerifier verifier = JWT.require(alg).withIssuer("my-service").build();
DecodedJWT decoded = verifier.verify(token);
System.out.println(decoded.getSubject());HS256 与 RS256
HS256 使用共享的对称密钥,简单易用,但签发方和验证方都必须彼此信任并共享该密钥。RS256 使用 RSA:用私钥签名,用公钥验证,适合多服务架构,因为任何服务都可以在不知道签名密钥的情况下进行验证。
存储 JWT:HttpOnly Cookie 与 localStorage
请将 JWT 存储在 HttpOnly Cookie 中(JS 无法访问,从而防止 XSS 窃取),并设置 Secure 和 SameSite=Strict 标志。请避免使用 localStorage,因为 XSS 攻击可以读取其中的内容。
// Set JWT as HttpOnly cookie in Spring:
ResponseCookie cookie = ResponseCookie.from("jwt", token)
.httpOnly(true).secure(true).sameSite("Strict")
.path("/").maxAge(3600).build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());刷新令牌
JWT 的有效期很短(15 分钟)。刷新令牌(不透明,存储在服务器端)的有效期更长。客户端可以使用刷新令牌换取新的 JWT,而无需重新进行身份验证。
JWT 撤销挑战
JWT 是无状态的,没有内置的撤销机制。请使用较短的有效期,并在 Redis 中维护已撤销 JWT ID 的阻止列表(jti 声明),以便在令牌过期前支持退出登录。
// On logout, add the jti to a Redis blocklist with TTL = token expiry:
redis.set("revoked:" + jti, "1", ex, 3600);
// On verify, check blocklist:
if (redis.exists("revoked:" + decoded.getId())) throw new SecurityException("Token revoked");Spring Security JWT 集成
在 Spring Security 中,实现 JwtAuthenticationFilter extends OncePerRequestFilter,在每个请求中提取并验证 JWT,然后设置 SecurityContext。
String token = request.getHeader("Authorization").replace("Bearer ","");
DecodedJWT decoded = verifier.verify(token);
String userId = decoded.getSubject();
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(auth);快速检查
HS256 和 RS256 的 JWT 签名在结构上的关键区别是什么?
回顾
JWT = header.payload.signature(Base64URL)。使用 HMAC(HS256)或 RSA(RS256)进行签名。验证签名和 exp 声明。将 JWT 存储在 HttpOnly Cookie 中。使用较短的有效期和刷新令牌。通过 Redis 中的 jti 阻止列表撤销令牌。
用 AI 导师学习 Java — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 104
- 课程
- 374
常见问题解答
「JWT:结构、创建与验证」课时是免费的吗?
是的 — 「JWT:结构、创建与验证」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「JWT:结构、创建与验证」这节课中我会学到什么?
手动解码 JWT 结构,使用密钥创建签名令牌,并在不使用框架的情况下验证声明 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「JWT:结构、创建与验证」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。