JWT

171 阅读2分钟

JWT

流程图

image-20200726183248298

JWT的结构

  • 1.标头(Header)
  • 2.有效载荷(Payload)
  • 3.签名(Signature)
  • 因此,JWT通常为Header.Payload.Signature。

Header

标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法(例如HMAC SHA256或RSA),如:

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

然后会使用 Base64 编码组成 JWT 结构的第一部分。

Payload

令牌的第二部分是有效负载,包含有关数据。如:

{
 "sub": "1234567890",
 "name": "John Doe",
 "admin": true
}

同样的,它会使用 Base64 编码组成 JWT 结构的第二部分。 因为Base64是一种编码,是可逆的,所以不应该在负载里面加入任何敏感的数据。

Signature

  • Signature 需要使用编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。如:

    HMACSHA256(header + "." + payload,secret);

  • 实际上是对头部以及负载内容进行签名,如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,新的头部和负载形成的签名和JWT附带上的签名也是不一样的。

JWT实际使用

@Test
void testJWT() throws Exception{
    //1.生成JWT
    Date expireTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2022-01-22 14:00:00");
    //给payload中添加数据,一个数据是一个claim,过期时间其实就是一个claim(name是exp,value是过期时间.).
    String token=JWT.create().withClaim("userId",1).withClaim("username","wjl").withExpiresAt(expireTime).sign(Algorithm.HMAC256("wjl123"));
    System.out.println(token);
    //2.验证JWT
    //构建验证器
    JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256("wjl123")).build();
    //验证
    DecodedJWT decodedJWT=jwtVerifier.verify(token);
    //3.取出数据
    System.out.println("userId: "+decodedJWT.getClaim("userId").asInt());
    System.out.println("username: "+decodedJWT.getClaim("username").asString());
    System.out.println("过期时间: "+decodedJWT.getExpiresAt());
    //也可以这么获取过期时间
    System.out.println("过期时间: "+decodedJWT.getClaim("exp").asDate());
}

个人总结

  • JWT本质上和session作用一样,都是【认证+携带数据】(比只携带数据多了一个认证功能),但是比session更高效(和后端服务器无关)。
  • 在同一数据的情况下,JWT只和密钥有关。