Java JWT:用于Java和Android的JSON Web令牌

JWT根据维基百科的定义,JSON WEBToken(JWT,读作 [/dʒɒt/]),是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。


已签名JWT的压缩表示形式是一个由三部分组成的字符串,每部分由一个.

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY


每个部分都以base 64编码。第一部分是头部(header),至少需要指定用于签署JWT的算法。第二部分是身体(payload)。本部分包含此JWT的所有声明。最后一节是签名(signature)。它的计算方法是将标题和正文的组合通过标题中指定的算法进行计算。

1.头信息指定了该JWT使用的签名算法:

header ='{"alg":"HS256","typ":"JWT"}'

HS256 表示使用了 HMAC-SHA256 来生成签名。

2.消息体包含了JWT的意图:

payload ='{"loggedInAs":"admin","iat":1422779638}'//iat表示令牌生成的时间

3.未签名的令牌由base64url编码的头信息和消息体拼接而成(使用"."分隔),签名则通过私有的key计算而成:

key = 'secretkey' 

unsignedToken = encodeBase64(header) + '.' +encodeBase64(payload) 

signature = HMAC-SHA256(key, unsignedToken)

最后在未签名的令牌尾部拼接上base64url编码的签名(同样使用"."分隔)就是JWT了:

token = encodeBase64(header) + '.' +encodeBase64(payload) + '.' + encodeBase64(signature)

# token看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI

JWT常常被用作保护服务端的资源(resource),客户端通常将JWT通过HTTP的Authorizationheader发送给服务端,服务端使用自己保存的key计算、验证签名以判断该JWT是否可信:

Authorization: BearereyJhbGci*...<snip>...*yu5CSpyHI

测试代码:

public class JwtUtilsTest {
   
/**
    
* 创建jwt
    
*
     * @param id
    
* @param subject
    
* @return
    
* @throws Exception
    
*/
   
public String createJWT(String id, String subject) throws Exception {
       
//指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
       
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
       
//生成JWT的时间
       
long nowMillis = System.currentTimeMillis();
       
Date now = new Date(nowMillis);
       
//创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
       
Map<String, Object> claims = new HashMap<String, Object>();
       
claims.put("uid", "1000000001");
       
//生成签名的时候使用的秘钥secret
       
SecretKey key = generalKey();
       
//payload添加各种标准声明和私有声明了
       
JwtBuilder builder = Jwts.builder()
               
.setClaims(claims)
               
.setId(id)
               
.setIssuedAt(now)
               
.setSubject(subject)
               
//  设置签名使用的签名算法和签名使用的秘钥
               
.signWith(signatureAlgorithm, key);

               
//  如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builderclaim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的

               
//  iss: jwt签发者
               
//  Claims setIssuer(String var1);

               
//sub:jwt所面向的用户,这个是一个json格式的字符串,可以存放userid之类的,作为用户的唯一标志。
               
//Claims setSubject(String var1);

               
//  aud: 接收jwt的一方
               
//  Claims setAudience(String var1);

               
//  exp: jwt的过期时间,这个过期时间必须要大于签发时间
               
//  Claims setExpiration(Date var1);

               
//  nbf: 定义在什么时间之前,该jwt都是不可用的.
               
//  ClaimssetNotBefore(Date var1);

                //  iat: jwt的签发时间
               
//  Claims setIssuedAt(Date var1);

               
//  设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
               
//  Claims setId(String var1);

       
return builder.compact();
   
}

   
/**
    
* 解密jwt
    
*
     * @param jwt
    
* @return
    
* @throws Exception
    
*/
   
public Claims parseJWT(String jwt) throws Exception {
       
//签名秘钥,和生成的签名的秘钥一模一样
       
SecretKey key = generalKey();
       
//得到DefaultJwtParser
       
Claims claims = Jwts.parser()
               
//设置签名的秘钥
               
.setSigningKey(key)
               
//设置需要解析的jwt
               
.parseClaimsJws(jwt).getBody();
       
return claims;
   
}

   
/**
    
* 由字符串生成加密key
    
*
     * @return
     */
    public SecretKey generalKey() {
       
//本地配置文件中加密的密文JWT_SECRET_KEY
       
String stringKey = "JWT_SECRET_KEY";
       
byte[] encodedKey = Base64.decodeBase64(stringKey);
       
// 根据给定的字节数组使用AES加密算法构造一个密钥,使用 encodedKey中的始于且包含 0 到前 leng 个字节这是当然是所有。
       
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
       
return key;
   
}

   
public staticvoid main(String[] args) throws Exception {
       
JwtUtilsTest utils = new JwtUtilsTest();
       
String user = utils.createJWT("jwt", "{id:10001,name:zhangsan}");
    
   System.out.println(user);

       
String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiIxMDAwMDAwMDAxIiwic3ViIjoie2lkOjEwMDAxLG5hbWU6emhhbmdzYW59IiwiaWF0IjoxNTI4MzYyNzI1LCJqdGkiOiJqd3QifQ.Yw0iKM_yTdwUHbBFpMc9Gf2eVgpE9czw2RuG8soS_3c";
       
Claims c = utils.parseJWT(jwt);
       
//{uid=1000000001, sub={id:10001,name:zhangsan}, iat=1528362725, jti=jwt}
       
System.out.println(c.toString());
   
}
}


猜你喜欢

转载自blog.csdn.net/qq_35098526/article/details/80612708
今日推荐