JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),定义了一种简介的,自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任,JWT可以使用HMAC算法
或使用RSA的公钥/私钥来签名,防止被篡改
官网: https://jwt.io
标准: https://tools.ietf.org/html/rfc7519
JWT令牌的优点:
1.jwt基于json,非常方便解析
2.可以在令牌中自定义丰富的内容,易扩展
3.通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高
4.资源服务使用JWT可不依赖认证服务即可完成授权
缺点:
1.JWT令牌较长,占存储空间比较大
JWT 实际上就是一个字符串 · 它由三部分组成,头部、荷载与签名
头部用于描述关于该 JWT 的最基本的信息,例如其类型(即 JWT )以及签名所用的算法(如 HMAC SHAZS6 或 RSA ) 等.这也可以被表示成一个 JS0N 对象.
{
"alg" : "HS256"
"typ" : " JWT"
}
第二部分是负载,就是存放有效信息的地方.这个名字像是特指飞机上承载的货品这些有效信息包含三个部分:
标准中注册的声明(建议但下强制使用)
iss:签发者
sub: jwt所面向61用户
aud:接收]的一方
exp: 的过期时间,这个道明叼间必纪要大于签发叼问
nbf:定义在什么叼间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的咆一身份而识,主要用未作为一次性token,从而回应重放攻击
{
Hsub-: 1234567890”,
"name": "John Doe*,
Miat": 1516239022
}
其中sub是标准的声明,name是自定义的声明(公共的或私有的)
然后将其进行base64编码,得到JwtM第二部分:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbWVzIiwiYWRtaW4iOnRydWV9
提示:声明中不要放一些敏感信息。
jwtM第三部分是一个受证信息,这个签证信息由三部分组成:
JJWT是i 盘供流到端的JWT创建和验证的Java库,小近免费和开源(Apache license版工2 0), JJW泡容易使用
和理怅,它被设计成以建筑力中心的流畅界面,隐藏了它的才部分复杂性.
规范官网 https://jwt.io
<parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.12.RELEASE</version> <relativePath/> </parent> <groupId>org.rzk</groupId> <artifactId>JWT-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--jwt依赖--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
由于时间戳不一样 Date ,所生成的token也不一样
/** * 创建token */ @Test public void JwtTestBuild(){ JwtBuilder jwtBuilder = Jwts.builder() //设置Id {"jti":"888"} .setId("888") //签发用户 {"sub":"888"} .setSubject("Rose") //签发时间 {"iat":"888"} .setIssuedAt(new Date()) //盐 .signWith(SignatureAlgorithm.HS256,"abcd"); String token = jwtBuilder.compact(); System.out.println(token); String[] split = token.split("\\."); //头部 System.out.println(Base64Codec.BASE64.decodeToString(split[0])); //负载 System.out.println(Base64Codec.BASE64.decodeToString(split[1])); //签名,乱码 System.out.println(Base64Codec.BASE64.decodeToString(split[2])); }
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwMTUyfQ.sT0LtxqdOrV3E_8gZK_iCWZtjof8hFRnP-3R0ACc5P0
{"alg":"HS256"}
{"jti":"888","sub":"Rose","iat":1641400152
�=��:�w�* �f���EFs�G@s��
@Test public void parseToken(){ String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwMTUyfQ.sT0LtxqdOrV3E_8gZK_iCWZtjof8hFRnP-3R0ACc5P0"; //获取claims荷载 Claims body = Jwts.parser() .setSigningKey("abcd") .parseClaimsJws(token).getBody(); System.out.println("jti:"+body.getId()); System.out.println("sub:"+body.getSubject()); System.out.println("iat:"+body.getIssuedAt()); }
jti:888
sub:Rose
iat:Thu Jan 06 00:29:12 CST 2022
/** * 创建token 过期时间 */ @Test public void JwtTestBuildExp(){ long timeMillis = System.currentTimeMillis(); //过期时间 一分钟 long expTime = timeMillis + 60 * 1000; JwtBuilder jwtBuilder = Jwts.builder() //设置Id {"jti":"888"} .setId("888") //签发用户 {"sub":"888"} .setSubject("Rose") //签发时间 {"iat":"888"} .setIssuedAt(new Date()) //盐 .signWith(SignatureAlgorithm.HS256, "abcd") //过期时间 .setExpiration(new Date(expTime)); String token = jwtBuilder.compact(); System.out.println(token); String[] split = token.split("\\."); //头部 System.out.println(Base64Codec.BASE64.decodeToString(split[0])); //负载 System.out.println(Base64Codec.BASE64.decodeToString(split[1])); //签名,乱码 System.out.println(Base64Codec.BASE64.decodeToString(split[2])); }
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwNTU3LCJleHAiOjE2NDE0MDA2MTd9.KpbHFkAb6Ov3QWyPM1IIODWWI4L7WzOakqSmYRYtKRs
{"alg":"HS256"}
{"jti":"888","sub":"Rose","iat":1641400557,"exp":1641400617}
*��@���Al�385�#��[3����a-
//解析token 过期时间 @Test public void parseTokenExp(){ String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwNTU3LCJleHAiOjE2NDE0MDA2MTd9.KpbHFkAb6Ov3QWyPM1IIODWWI4L7WzOakqSmYRYtKRs"; //获取claims荷载 Claims body = Jwts.parser() .setSigningKey("abcd") .parseClaimsJws(token).getBody(); System.out.println("jti:"+body.getId()); System.out.println("sub:"+body.getSubject()); System.out.println("iat:"+body.getIssuedAt()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("当前时间:"+format.format(new Date())); System.out.println("过期时间:"+format.format(body.getExpiration())); }
jti:888
sub:Rose
iat:Thu Jan 06 00:35:57 CST 2022
当前时间:2022-01-06 00:36:45
过期时间:2022-01-06 00:36:57
会报失效JWT异常
JWT失效时间在2022-01-06T00:36:57Z 当前时间 2022-01-06T00:37:47Z 超过50003 milliseconds
JWT expired at 2022-01-06T00:36:57Z. Current time: 2022-01-06T00:37:47Z, a difference of 50003 milliseconds. Allowed clock skew: 0 milliseconds.