该系列文章主要是对 hutool 工具类的介绍,详情可以参考
hutool 提供了零依赖的JWT(JSON Web Token)实现。
- jwt 结构
- Header 头部信息,主要声明了JWT的签名算法等信息
- Payload 载荷信息,主要承载了各种声明并传递明文数据
- Signature 签名,拥有该部分的JWT被称为JWS,也就是签了名的JWS,用于校验数据
JWT 头
JWT 头部分是一个描述 JWT 元数据的 JSON 对象,通常如下所示。
{ "alg": "HS256", "typ": "JWT" }
alg 属性表示签名使用的算法,默认为 HMAC SHA256(写为 HS256)
typ 属性表示令牌的类型,JWT 令牌统一写为 JWT。
最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存。
有效载荷
有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。
- iss:发行人
- exp:到期时间
- sub:主题
- aud:用户
- nbf:在此之前不可用
- iat:发布时间
- jti:JWT ID用于标识该JWT
请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。
签名哈希
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。
主要提供的功能:
- JWT创建
- JWT解析
- JWT验证
@Test
public void createTest() {
byte[] key = "helloworld".getBytes();
Map<String, Object> map = new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put("uid", Integer.parseInt("123"));
// 10 秒后失效
put(JWTPayload.EXPIRES_AT, System.currentTimeMillis() + 1000 * 10);
}
};
String token = JWTUtil.createToken(map, key);
Console.log(token);
}
@Test
public void parseTest() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMywiZXhwIjoxNjYzNzI2Mzg2NTQ0fQ.yZtjlrV5hN8hWdFOZLJNqoaNaand-1XW0Pi1YIwmCrk";
final JWT jwt = JWTUtil.parseToken(token);
//header
JSONObject headers = jwt.getHeaders();
Console.log(headers);
//payload
JSONObject payloads = jwt.getPayloads();
Console.log(payloads);
}
@Test
public void verifyTest() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMywiZXhwIjoxNjYzNzI2Mzg2NTQ0fQ.yZtjlrV5hN8hWdFOZLJNqoaNaand-1XW0Pi1YIwmCrk";
final boolean verify = JWTUtil.verify(token, "helloworld".getBytes());
Assert.assertTrue(verify);
}
@Test
public void validateTest() {
JWT jwt = JWT.create()
.setPayload("test", "test")
.setKey("helloworld".getBytes(StandardCharsets.UTF_8))
.setIssuedAt(DateUtil.date())
.setExpiresAt(DateUtil.parse("2022-09-21 10:37:00"));
String token = jwt.sign();
ThreadUtil.safeSleep(1000 * 60);
JWTValidator.of(token).validateDate();
}