JWT简介
JWT(json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。
JWT的构成
jwt由三个部分组成
第一部分:头部(header),第二部分:playload(称为载荷),第三部分:signature(签证)
header
jwt的头部承载两部分信息:
-
声明类型,这里是jwt
-
声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:
{
"typ": "JWT",
"alg": "HS256"
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。
playload
载荷是存放有效信息的地方,包含三个部分
-
标准中注册的声明
-
公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用)
iss | jwt签发者 |
sub | jwt所面向的用户 |
aud | 接收jwt的一方 |
exp | jwt的过期时间,这个过期时间必须要大于签发时间 |
nbf | 定义在什么时间之前,该jwt都是不可用的. |
iat | jwt的签发时间 |
jti | jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 |
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:
{
"name":"chenkeqiang",
"age":"24",
"city":"shanghai"
}
然后将其进行base64加密,得到Jwt的第二部分
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
-
header (base64后的)
-
payload (base64后的)
-
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分
gradle添加依赖
compile group: 'com.auth0', name: 'java-jwt', version: '3.8.0'
类似于maven添加依赖,都是引入需要的东西。
下面上代码。。。。。
package com.ssh.pmhc.store.test;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @Version: 1.0
* @Author CKQ
* @Date 2019/6/6 9:53
*/
public class JwtToken {
// 公用秘钥,保存在服务端
public static String SECRET = "CKQ";
/**
* 生成token
* @return
*/
public static String createToken(){
// 签发时间
Date iatDate = new Date();
// 过期时间 - 2分钟
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.MINUTE,1);
Date expireDate = nowTime.getTime();
Map<String,Object> map = new HashMap<>();
map.put("alg","HS256");
map.put("typ","JWT");
String token = JWT.create().withHeader(map) // header
.withClaim("name","ckq") // playload
.withClaim("age","24")
.withClaim("city","上海")
.withExpiresAt(expireDate) // 设置过期时间 ,过期时间要大于签发时间
.sign(Algorithm.HMAC256(SECRET)); // 加密
return token;
}
/**
* 解密token
* @param token
* @return
*/
public static Map<String, Claim> verifyToken(String token){
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
DecodedJWT jwt = null;
try{
jwt = verifier.verify(token);
}catch (Exception e){
throw new RuntimeException("已过期..");
}
return jwt.getClaims();
}
}
测试上面的代码
package com.ssh.pmhc.store.test;
import com.auth0.jwt.interfaces.Claim;
import java.util.Map;
/**
* @Version: 1.0
* @Author chenkeqiang
* @Date 2019/6/6 10:08
*/
public class TestJwt {
public static void main(String[] args) {
String token = JwtToken.createToken();
System.out.println("生成的token: "+token);
Map<String, Claim> claimMap = JwtToken.verifyToken(token);
System.out.println(claimMap.get("name").asString());
System.out.println(claimMap.get("age").asString());
System.out.println(claimMap.get("city").asString());
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmciOiLkuIrmtbciLCJuYW1lIjoi6ZmI5YWL5by6IiwiZXhwIjoxNTU5Nzg3MTU2LCJhZ2UiOiIyNCJ9.yRY8coBAit5Dza9KfSoQIPhyPzDs9Yah65D_R3VtlZA
// 过期测试
System.out.println("过期测试--------------------");
// 过期的token
String expireToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmciOiLkuIrmtbciLCJuYW1lIjoi6ZmI5YWL5by6IiwiZXhwIjoxNTU5Nzg3MTU2LCJhZ2UiOiIyNCJ9.yRY8coBAit5Dza9KfSoQIPhyPzDs9Yah65D_R3VtlZA";
Map<String, Claim> stringClaimMap = JwtToken.verifyToken(expireToken);
}
}
运行结果
生成的token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaXR5Ijoi5LiK5rW3IiwibmFtZSI6ImNrcSIsImV4cCI6MTU1OTc4ODQyOCwiYWdlIjoiMjQifQ.RAvwu5Vxj1W16AFXncxK69WRiFLKW5ZbqWEgXka7ydo
ckq
24
上海
过期测试--------------------
Exception in thread "main" java.lang.RuntimeException: 已过期..
at com.ssh.pmhc.store.test.JwtToken.verifyToken(JwtToken.java:64)
at com.ssh.pmhc.store.test.TestJwt.main(TestJwt.java:28)