JWT 是什么?JWT 如何防篡改?JWT 使用【hutools 工具包】
JWT 是什么
JWT(JSON Web Token)是一种用于身份验证和授权的开放标准(RFC 7519),它通过在网络应用之间传输信息的方式来安全地传递声明。JWT 是一串 BASE64 编码,通过 ". " 分割成三部分,分别是:头部(Header)、载荷(Payload)和签名(Signature)。
JWT 结构
- 头部(Header):包含了JWT的类型和签名算法等信息。头部一般由两部分组成,类型是'JWT',算法通常使用HMAC SHA256 或 RSA 等。
- 载荷(Payload):包含了一组声明(claims),用于描述用户或其他实体的信息。载荷可以包含标准声明(比如用户ID、过期时间)和自定义声明。载荷的内容是可读的,但不能信任,因为它没有经过签名验证。
- 签名(Signature):使用密钥对头部和载荷进行签名,以确保JWT的完整性和认证。签名的过程是将头部和载荷以及一个密钥作为输入,通过指定的签名算法生成签名。接收方可以使用相同的密钥和算法对签名进行验证。
JWT 防篡改原理
JWT 中签名部分是通过 头部 以及 载荷 的 Base64 字符串通过 "." 号拼接,然后再通过头部中指定的加密算法(比如:HS256)生成签名,然后在转换成 base64,最后 头部、载荷、签名通过 "." 拼接成 jwt token 串
这就意味着,我只要按照同样的方法生成签名,然后对比就知道有没有被篡改
import hmac
import hashlib
import base64header = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9"
payload = "eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvbmQgRG9lIiwgImlhdCI6IDE1MTYyMzkwMjJ9"
secret = "your-256-bit-secret"# 将头部和载荷用点号连接
message = f"{header}.{payload}"# 使用 HMAC-SHA256 生成签名
signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest()# 将签名进行 Base64Url 编码
encoded_signature = base64.urlsafe_b64encode(signature).rstrip(b'=').decode()
引入依赖
注意:低版本的没有 jwt
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>
创建 token
Document
@Test
void test(){Map<String, Object> map = new HashMap<>();map.put("userId", 100343);map.put("hhh", "test11231");String key = "w^&d*c!j^@8a%4&dm1Cg0i^N%03b$5^mHc3N";// map 为 载荷信息,key:为密钥,防篡改的,注意不可以泄露出去String token = JWTUtil.createToken(map, key.getBytes());System.out.println(token);
}
校验 token
@Test
void test(){Map<String, Object> map = new HashMap<>();map.put("userId", 100343);map.put("hhh", "test11231");String key = "w^&d*c!j^@8a%4&dm1Cg0i^N%03b$5^mHc3N";// map 为 载荷信息,key:为密钥,防篡改的,注意不可以泄露出去String token = JWTUtil.createToken(map, key.getBytes());// 验证是否有效boolean verify = JWTUtil.verify(token, key.getBytes());System.out.println(verify);
}
解析 token
@Test
void test2(){Map<String, Object> map = new HashMap<>();map.put("userId", 100343);map.put("hhh", "test11231");String key = "w^&d*c!j^@8a%4&dm1Cg0i^N%03b$5^mHc3N";// map 为 载荷信息,key:为密钥,防篡改的,注意不可以泄露出去String token = JWTUtil.createToken(map, key.getBytes());// 验证是否有效boolean verify = JWTUtil.verify(token, key.getBytes());if (!verify){throw new RuntimeException("token 无效!");}// 解析 tokenJWT jwt = JWTUtil.parseToken(token);// 头部信息JSONObject headers = jwt.getHeaders();// 载荷信息JSONObject payloads = jwt.getPayloads();System.out.println(payloads.get("userId"));
}