什么是JWT令牌?
JWT是JSON Web Token的缩写,即JSON Web令牌,是一种无状态(服务端不存储)的自包含令牌(自身包含数据)。
JWT的作用
JWT 最重要的作用就是对 token信息的防伪作用
JWT的原理
一个JWT由三个部分组成:JWT头、有效载荷、签名哈希
最后由这三者组合进行base64编码得到JWT
JWT令牌的组成
-
JWT头:
-
JWT头部分是一个描述JWT元数据的JSON对象
-
-
有效载荷:
-
有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。
-
sub: 主题 iss: jwt签发者 aud: 接收jwt的一方 iat: jwt的签发时间 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
-
也可以自定义字段
-
"userName": "Chen", "admin": true, "avatar": "Chen.jpg"
-
-
签名哈希:
-
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
-
JWT的用法
客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。
当跨域时,也可以将JWT放置于POST请求的数据主体中。
JWT问题和趋势
1、JWT默认不加密,但可以加密。生成原始令牌后,可以使用该令牌再次对其进行加密。
2、当JWT未加密时,一些私密数据无法通过JWT传输。
3、JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
4、JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
5、JWT本身包含认证信息,因此一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行身份验证。
6、为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。
JWT整合
添加pom依赖
<dependencies>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
生成token
public class JwtTests {
//过期时间,毫秒,24小时
private static long tokenExpiration = 24*60*60*1000;
//秘钥:越复杂越好
private static String tokenSignKey = "ChenHaiTao";
@Test
public void testCreateToken(){
String token = Jwts.builder()
//头部信息
.setHeaderParam("typ", "JWT") //令牌类型
.setHeaderParam("alg", "HS256") //签名算法
//固定有效载荷
.setSubject("token-theme") //令牌主题
.setIssuer("wystawca")//签发者
.setAudience("receiver")//接收者
.setIssuedAt(new Date())//签发时间
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) //过期时间
.setNotBefore(new Date(System.currentTimeMillis() + 20*1000)) //20秒后可用
.setId(UUID.randomUUID().toString())
//自定义有效载荷
.claim("userName", "Chen")
.claim("avatar", "Chen.jpg")
//签名哈希
.signWith(SignatureAlgorithm.HS256, tokenSignKey)//签名哈希
.compact(); //转换成字符串
System.out.println(token);
}
}
解析token
@Test
public void testGetUserInfo(){
String token = "jwt字符串";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
String subject = claims.getSubject();
String issuer = claims.getIssuer();
String audience = claims.getAudience();
Date issuedAt = claims.getIssuedAt();
Date expiration = claims.getExpiration();
Date notBefore = claims.getNotBefore();
String id = claims.getId();
System.out.println(subject);
System.out.println(issuer);
System.out.println(audience);
System.out.println(issuedAt);
System.out.println(expiration);
System.out.println(notBefore);
System.out.println(id);;
String nickname = (String)claims.get("userName");
String avatar = (String)claims.get("avatar");
System.out.println(nickname);
System.out.println(avatar);
}