jwt应该如何使用呢?
下面来写一个最简单的jwt的使用demo
1. 引入依赖包:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
2. 加密解密方法
public static void main(String[] args) {
// 过期时间
final Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 1000);
// 以abc为密钥进行hmac256方法加密,保存 a,b两个属性
final String token = JWT.create().withHeader(new HashMap<>())
.withClaim("a", "ccc")
.withClaim("b", JSONObject.toJSON(Arrays.asList("a", "b", "c")).toString())
.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256("abc"));
System.out.println("token = " + token);
// 解密
JWTVerifier build = JWT.require(Algorithm.HMAC256("abc")).build();
final DecodedJWT verify = build.verify(token);
// 取出a
final Claim a = verify.getClaim("a");
System.out.println("a = " + a);
System.out.println("a.asString() = " + a.asString());
// 取出b
final Claim b = verify.getClaim("b");
System.out.println("b = " + b);
System.out.println("b.asArray(List.class) = " + b.asString());
// 取出过期时间
final Date expiresAt = verify.getExpiresAt();
System.out.println("expiresAt = " + expiresAt.toLocaleString());
}
在生产环境中,一般jwt会保存用户的名字和角色权限等信息。可以将token 写到cookie里,每次前端访问后台时,可以在拦截器或者过滤器取到token, 然后解密,先判断是否过期,过期就抛异常阻止其访问。然后取出信息保存到threadLocal里,方便以后调用这些信息,当后台访问完成后,从thredLocal删除此用户信息。
3. 如何使用
登陆返回JWT, 客户端浏览器拿到这个 JWT 字符串后,存储到 cookie 或者 浏览器的 LocalStorage 中。再次发送请求,比如请求用户设置页面的时候,在 HTTP 请求头中加入 JWT 字符串,或者直接放到请求主体中。
登录过后给前端进行返回JWT并设置了过期时间30分钟,后端接收请求的时候获取请求头出来进行jwt解析判断过期时间是否小于10分钟,如果小于10分钟就生成新的 jwt 在responseHearde进行返回即可,前端每次都检查responseHearde是否有jwt, 如果有,则替换localStorage 中的jwt .
jwt 结构解析
JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)
Header
JWT头是一个描述JWT元数据的JSON对象,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存
{
"alg": "HS256",
"typ": "JWT"
}
Payload
是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
这些预定义的字段并不要求强制使用。除以上默认字段外,我们还可以自定义私有字段,一般会把包含用户信息的数据放到payload中
{ "sub": "1234567890", "name": "Helen", "admin": true ,roles:["admin","comsumer"]}
Signature
签名哈希部分是对上面两部分数据签名,需要使用base64编码后的header和payload数据,通过指定的算法生成哈希,以确保数据不会被篡改。首先,需要指定一个密钥(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用.分隔,就构成整个JWT对象

注意JWT每部分的作用,在服务端接收到客户端发送过来的JWT token之后:
header和payload可以直接利用base64解码出原文,从header中获取哈希签名的算法,从payload中获取有效数据
signature由于使用了不可逆的加密算法,无法解码出原文,它的作用是校验token有没有被篡改。服务端获取header中的加密算法之后,利用该算法加上secretKey对header、payload进行加密,比对加密后的数据和客户端发送过来的是否一致。注意secretKey只能保存在服务端,而且对于不同的加密算法其含义有所不同,一般对于MD5类型的摘要加密算法,secretKey实际上代表的是盐值
JWT 有效期内可以
JWT 有个问题,那就是一旦颁发一个 JWT 令牌,服务端就没办法废弃掉它,除非等到它自身过期。有很多应用默认只允许最新登录的一个客户端正常使用,不允许多端登录,JWT 就没办法做到,因为颁发了新令牌,但是老的令牌在过期前仍然可用。这种情况下,就需要服务端增加相应的逻辑。
