1、JWT概念
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
头部(Header)
头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。
{"typ":"JWT","alg":"HS256"}
在头部指明了签名算法是HS256算法。 我们进行BASE64编码base64 转图片 在线解码编码,编码后的字符串如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
载荷(playload)
载荷就是存放有效信息的地方。
定义一个payload:
{"sub":"1234567890","name":"John Doe","admin":true}
然后将其进行base64加密,得到Jwt的第二部分。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
签证(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
2、JJWT签发与验证token
JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。
官方文档:
2.1、创建token
(1)新建项目jwtTest中的pom.xml中添加依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
(2) 创建测试类,代码如下
JwtBuilder builder= Jwts.builder()
.setId("888") //设置唯一编号
.setSubject("小白")//设置主题 可以是JSON数据
.setIssuedAt(new Date())//设置签发日期
.signWith(SignatureAlgorithm.HS256,"itcast");//设置签名 使用HS256算法,并设置SecretKey(字符串)
//构建 并返回一个字符串
System.out.println( builder.compact() );
运行打印结果:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDQxODF9.ThecMfgYjtoys3JX7dpx3hu6pUm0piZ0tXXreFU_u3Y
再次运行,会发现每次运行的结果是不一样的,因为我们的载荷中包含了时间。
2.2、解析token
我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。
String compactJwt="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDQxODF9.ThecMfgYjtoys3JX7dpx3hu6pUm0piZ0tXXreFU_u3Y";
Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJwt).getBody();
System.out.println(claims);
运行打印效果:
{jti=888, sub=小白, iat=1557904181}
试着将token或签名秘钥篡改一下,会发现运行时就会报错,所以解析token也就是验证token.
2.3、设置过期时间
有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添加一个过期时间。
(1)创建token 并设置过期时间
//当前时间
long currentTimeMillis = System.currentTimeMillis();
Date date = new Date(currentTimeMillis);
JwtBuilder builder= Jwts.builder()
.setId("888") //设置唯一编号
.setSubject("小白")//设置主题 可以是JSON数据
.setIssuedAt(new Date())//设置签发日期
.setExpiration(date)
.signWith(SignatureAlgorithm.HS256,"itcast");//设置签名 使用HS256算法,并设置SecretKey(字符串)
//构建 并返回一个字符串
System.out.println( builder.compact() );
解释:
.setExpiration(date) //用于设置过期时间 ,参数为Date类型数据
注意: 当前时间超过过期时间,则会报错。
2.4、自定义claims
我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims。
创建测试类,并设置测试方法:
创建token:
@Test
public void createJWT(){
//当前时间
long currentTimeMillis = System.currentTimeMillis();
currentTimeMillis+=1000000L;
Date date = new Date(currentTimeMillis);
JwtBuilder builder= Jwts.builder()
.setId("888") //设置唯一编号
.setSubject("小白")//设置主题 可以是JSON数据
.setIssuedAt(new Date())//设置签发日期
.setExpiration(date)//设置过期时间
.claim("roles","admin")//设置角色
.signWith(SignatureAlgorithm.HS256,"itcast");//设置签名 使用HS256算法,并设置SecretKey(字符串)
//构建 并返回一个字符串
System.out.println( builder.compact() );
}
运行打印效果:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDU4MDIsImV4cCI6MTU1NzkwNjgwMiwicm9sZXMiOiJhZG1pbiJ9.AS5Y2fNCwUzQQxXh_QQWMpaB75YqfuK-2P7VZiCXEJI
解析TOKEN:
//解析
@Test
public void parseJWT(){
String compactJwt="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NTc5MDU4MDIsImV4cCI6MTU1NzkwNjgwMiwicm9sZXMiOiJhZG1pbiJ9.AS5Y2fNCwUzQQxXh_QQWMpaB75YqfuK-2P7VZiCXEJI";
Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJwt).getBody();
System.out.println(claims);
}
运行效果: