Appearance
源码:labs/java/backend-data/auth-token-simulation/src/AuthTokenSimulation.java
- 原始路径:
labs/java/backend-data/auth-token-simulation/src/AuthTokenSimulation.java - 类型:
java
java
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* Token 鉴权仿真:JWT 结构 + 双 Token 无感刷新 + 并发 401 排队。
*
* 对应 docs 06-backend-data/06-auth-token-and-oauth2.md:
* 1. JWT 三段式(header.payload.signature):Header/Payload 只是 Base64,防篡改不防读取
* 2. 双 Token:access_token 短命(15min)+ refresh_token 长命(30d)
* 3. 并发 401 排队:多个请求同时 401,只刷新一次 token,其余复用新 token 重放
*
* 纯 Java CLI(无外部依赖,手写 Base64 演示 JWT 结构)。
* 运行:javac -d out src/AuthTokenSimulation.java && java -cp out AuthTokenSimulation
*/
public class AuthTokenSimulation {
public static void main(String[] args) {
System.out.println("========== 1. JWT 三段式结构(防篡改不防读取)==========");
String jwt = buildJwt("user_10086", "alex", "viewer");
String[] parts = jwt.split("\\.");
System.out.println(" JWT: " + jwt);
System.out.println(" Header (Base64 解码): " + decode(parts[0]));
System.out.println(" Payload (Base64 解码): " + decode(parts[1]));
System.out.println(" Signature: 对 header.payload 签名,任何人可读但不可改(改了就验签失败)");
System.out.println();
System.out.println("========== 2. 双 Token 生命周期 ==========");
System.out.println(" access_token: 15 分钟,请求头 Authorization: Bearer <access>");
System.out.println(" refresh_token: 30 天,仅用于换新 access_token(绝不进请求头)");
System.out.println();
System.out.println("========== 3. 并发 401 排队:只刷新一次 ==========");
// 模拟 10 个并发请求在 access_token 过期瞬间同时收到 401
int concurrent = 10;
int refreshCount = 0;
boolean tokenRefreshed = false;
for (int i = 0; i < concurrent; i++) {
if (!tokenRefreshed) {
synchronized (AuthTokenSimulation.class) {
if (!tokenRefreshed) { // Double-Check:只有第一个请求进临界区刷新
refreshCount++;
tokenRefreshed = true; // 模拟换到新 token
}
}
}
// 其余请求复用新 token 重放,不再刷新
}
System.out.println(" " + concurrent + " 个并发 401 请求,实际触发刷新次数 = " + refreshCount + "(其余复用新 token 重放)");
System.out.println();
System.out.println("========== 4. 结论 ==========");
System.out.println(" · JWT 内容任何人可读:Payload 只放非敏感标识,不放密码/手机号");
System.out.println(" · 双 Token 刷新必须串行化(OkHttp Authenticator / 并发锁),否则 401 风暴");
System.out.println(" · refresh_token 也失效时:静默跳登录页,避免死循环重试");
}
/** 构造 JWT(简化:签名用"伪签名"示意,真实是 HMAC/RSA) */
static String buildJwt(String userId, String name, String role) {
String header = encode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}");
String payload = encode("{\"sub\":\"" + userId + "\",\"name\":\"" + name
+ "\",\"role\":\"" + role + "\",\"exp\":1770000000}");
String signature = "fake_signature_for_demo"; // 真实:HMAC-SHA256(header.payload, secret)
return header + "." + payload + "." + signature;
}
static String encode(String s) {
return Base64.getUrlEncoder().withoutPadding()
.encodeToString(s.getBytes(StandardCharsets.UTF_8));
}
static String decode(String s) {
return new String(Base64.getUrlDecoder().decode(s), StandardCharsets.UTF_8);
}
}