基于JJWT理解JWT,JWS,JWE

JWT , 全写JSON Web Token, 是开放的行业标准RFC7591,用来实现端到端安全验证.
从开发者理解的角度来说:

  • JWT 是一个定义传递信息的标准
  • JWT 的Token是一个Base64编码的字符串, 类似
eyJhbGciOiJIUzI1NyJ9.eyJzdWIiOiJvc2NhciJ9.p1no61S/XIQ0QNEhzB8e0eI9Q39jIGgkDxUjYipKnzw=

这个字符串里面包含2个点号(.),可以分成3段, 分别表示头部,负载和签名。

关于JWT的更多介绍,可以参考:
JWT介绍以及java-jwt的使用

JWT Token是如何产生的

  1. 最简单的JWT由两部分组成: header(头部) 和 payload(负载)
    关于JWT的基本介绍, 可以参考:
    JWT介绍以及java-jwt的使用

比如头部是:

{
  "alg": "none"
}

负载是:

Hello, JWT
  1. 移除不必要的空格
		String header = "{\"alg\":\"none\"}";
		String payload= "Hello, JWT";
  1. 获取UTF-8的字节后,使用Base64进行编码
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());

4.将编码后的字符使用点号(.) 连接起来

String compact= encodedHeader + "." + encodedPayload + ".";

连接后的Token如下:

eyJhbGciOiJub25lIn0=.SGVsbG/vvIwgSldU.

从这里可以看出, JWT其实并不神秘, 只是对字符串进行了Base64编码, 所以通过解码或是一些在线的Base64解码的工具就可以直接得到结果了,比如 https://base64.us/
在这里插入图片描述

因为没有进行数字签名,上面的Token是不安全和未受保护的, 不能保证没有第三方对这个内容进行修改,所以为了提升安全,就需要添加数字签名。

JWS ,signedJWT -加密签名的JWT

上面的示例payload是一个字符串, 但实际使用时,payload更多是JSON 格式的数据, 对JWT进行数字签名后的Token 就称为JWS了。

还是从简单的示例来看:

  1. 头部
{
  "alg": "HS256"
}

使用HS256算法进行数字签名
2. 负载

{
"sub":"oscar"
}
  1. 去除空格的内容
		String header = "{\"alg\":\"HS257\"}";
		String payload=  "{\"sub\":\"oscar\"}";
  1. 获取字节数组和使用Base64编码,并且使用点号连接
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;
  1. 使用足够安全的摘要加密算法(比如使用HMAC-SHA-256), 获取加密后的摘要,也就是数字签名。最后将头部、负载和签名组合起来就是一个完整的Token 了。
		String header = "{\"alg\":\"HS257\"}";
		String payload=  "{\"sub\":\"oscar\"}";
		Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;
		
		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        sha256_HMAC.init(secretKey);
        byte[] signature = sha256_HMAC.doFinal(concatenated.getBytes("utf-8"));//使用加密算法产生签名
        String compact = concatenated + '.' + Base64.getEncoder().encodeToString( signature ); //将签名和头,载荷连接起来
        System.out.println(compact);

由此产生的Token如下:

eyJhbGciOiJIUzI1NyJ9.eyJzdWIiOiJvc2NhciJ9.HjomJsGXx3vO/x16euJo7kFsBFJaOEdyoj5Czbt3XE4=

JWE,  encrypted JWT

JWE就是对数字签名的Token进行加密,加密之后使用Base64解码之后是无法直接获取Token的内容的, 加密的方式可以是对称加密, 可以是非对称加密。JJWT也提供了一些加密的快速方法, 但是在不同的版本中支持有差异, 这里使用Java 本身的DES对称加密进行演示。
示例代码如下:

	
	@Test
	public void jwe() throws Exception {
		String header = "{\"alg\":\"HS257\"}";
		String payload = "{\"sub\":\"oscar\"}";
		Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;

		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
		sha256_HMAC.init(secretKey);
		byte[] signature = sha256_HMAC.doFinal(concatenated.getBytes("utf-8"));
		String compact = concatenated + '.' + Base64.getEncoder().encodeToString(signature);
		
		//使用DES算法对称加密
		String strKey = "this is my password";
		DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey key = keyFactory.generateSecret(desKeySpec);

		Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, key);

		byte[] encryptedBytes = cipher.doFinal(compact.getBytes(StandardCharsets.UTF_8));
		String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
		System.out.println(encryptedText);
		
	}

加密之后的Token使用Base64解码后得到的内容如下:
在这里插入图片描述

要得到正确的内容, 需要使用密钥进行解密之后, 再进行Base64解码。

关于Java对称加密与解密, 可以参考:
Java实现对称加密(DES,AES)快速入门示例

名词解释

  • JWT, JSON Web Token。 JSON格式的Web令牌
  • JWS: signed JWT,签名的JWT
  • JWE: encrypted JWT,签名且加密的JWT(对负载也加密)

三者的关系如下:
在这里插入图片描述

完整示例代码



猜你喜欢

转载自blog.csdn.net/oscar999/article/details/132418249