From 8080093ba53070a73b940d4348dca370cc470c9f Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 10 Jun 2021 16:26:31 +0800 Subject: [PATCH] add hutool-jwt --- .../java/cn/hutool/crypto/digest/HMac.java | 75 +++++++++++-------- .../main/java/cn/hutool/json/jwt/Claims.java | 25 ++----- .../src/main/java/cn/hutool/json/jwt/JWT.java | 37 ++++++++- .../java/cn/hutool/json/jwt/JWTHeader.java | 2 +- .../main/java/cn/hutool/json/jwt/Signer.java | 6 -- .../cn/hutool/json/jwt/signers/JWTSigner.java | 17 +++++ hutool-jwt/pom.xml | 29 +++++++ pom.xml | 1 + 8 files changed, 133 insertions(+), 59 deletions(-) delete mode 100644 hutool-json/src/main/java/cn/hutool/json/jwt/Signer.java create mode 100644 hutool-json/src/main/java/cn/hutool/json/jwt/signers/JWTSigner.java create mode 100644 hutool-jwt/pom.xml diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/HMac.java b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/HMac.java index 974f021bd..85a0ecb83 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/digest/HMac.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/digest/HMac.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.InputStream; import java.io.Serializable; import java.security.Key; +import java.security.MessageDigest; /** * HMAC摘要算法
@@ -28,9 +29,9 @@ import java.security.Key; */ public class HMac implements Serializable { private static final long serialVersionUID = 1L; - + private final MacEngine engine; - + // ------------------------------------------------------------------------------------------- Constructor start /** * 构造,自动生成密钥 @@ -39,7 +40,7 @@ public class HMac implements Serializable { public HMac(HmacAlgorithm algorithm) { this(algorithm, (Key)null); } - + /** * 构造 * @param algorithm 算法 {@link HmacAlgorithm} @@ -48,7 +49,7 @@ public class HMac implements Serializable { public HMac(HmacAlgorithm algorithm, byte[] key) { this(algorithm.getValue(), key); } - + /** * 构造 * @param algorithm 算法 {@link HmacAlgorithm} @@ -57,7 +58,7 @@ public class HMac implements Serializable { public HMac(HmacAlgorithm algorithm, Key key) { this(algorithm.getValue(), key); } - + /** * 构造 * @param algorithm 算法 @@ -67,7 +68,7 @@ public class HMac implements Serializable { public HMac(String algorithm, byte[] key) { this(algorithm, new SecretKeySpec(key, algorithm)); } - + /** * 构造 * @param algorithm 算法 @@ -77,7 +78,7 @@ public class HMac implements Serializable { public HMac(String algorithm, Key key) { this(MacEngineFactory.createEngine(algorithm, key)); } - + /** * 构造 * @param engine MAC算法实现引擎 @@ -87,11 +88,11 @@ public class HMac implements Serializable { this.engine = engine; } // ------------------------------------------------------------------------------------------- Constructor end - + // ------------------------------------------------------------------------------------------- Digest /** * 生成文件摘要 - * + * * @param data 被摘要数据 * @param charset 编码 * @return 摘要 @@ -99,20 +100,20 @@ public class HMac implements Serializable { public byte[] digest(String data, String charset) { return digest(StrUtil.bytes(data, charset)); } - + /** * 生成文件摘要 - * + * * @param data 被摘要数据 * @return 摘要 */ public byte[] digest(String data) { return digest(data, CharsetUtil.UTF_8); } - + /** * 生成文件摘要,并转为16进制字符串 - * + * * @param data 被摘要数据 * @param charset 编码 * @return 摘要 @@ -120,21 +121,21 @@ public class HMac implements Serializable { public String digestHex(String data, String charset) { return HexUtil.encodeHexStr(digest(data, charset)); } - + /** * 生成文件摘要 - * + * * @param data 被摘要数据 * @return 摘要 */ public String digestHex(String data) { return digestHex(data, CharsetUtil.UTF_8); } - + /** * 生成文件摘要
* 使用默认缓存大小,见 {@link IoUtil#DEFAULT_BUFFER_SIZE} - * + * * @param file 被摘要文件 * @return 摘要bytes * @throws CryptoException Cause by IOException @@ -148,52 +149,52 @@ public class HMac implements Serializable { IoUtil.close(in); } } - + /** * 生成文件摘要,并转为16进制字符串
* 使用默认缓存大小,见 {@link IoUtil#DEFAULT_BUFFER_SIZE} - * + * * @param file 被摘要文件 * @return 摘要 */ public String digestHex(File file) { return HexUtil.encodeHexStr(digest(file)); } - + /** * 生成摘要 - * + * * @param data 数据bytes * @return 摘要bytes */ public byte[] digest(byte[] data) { return digest(new ByteArrayInputStream(data), -1); } - + /** * 生成摘要,并转为16进制字符串
- * + * * @param data 被摘要数据 * @return 摘要 */ public String digestHex(byte[] data) { return HexUtil.encodeHexStr(digest(data)); } - + /** * 生成摘要,使用默认缓存大小,见 {@link IoUtil#DEFAULT_BUFFER_SIZE} - * + * * @param data {@link InputStream} 数据流 * @return 摘要bytes */ public byte[] digest(InputStream data) { return digest(data, IoUtil.DEFAULT_BUFFER_SIZE); } - + /** * 生成摘要,并转为16进制字符串
* 使用默认缓存大小,见 {@link IoUtil#DEFAULT_BUFFER_SIZE} - * + * * @param data 被摘要数据 * @return 摘要 */ @@ -203,7 +204,7 @@ public class HMac implements Serializable { /** * 生成摘要 - * + * * @param data {@link InputStream} 数据流 * @param bufferLength 缓存长度,不足1使用 {@link IoUtil#DEFAULT_BUFFER_SIZE} 做为默认值 * @return 摘要bytes @@ -211,11 +212,11 @@ public class HMac implements Serializable { public byte[] digest(InputStream data, int bufferLength) { return this.engine.digest(data, bufferLength); } - + /** * 生成摘要,并转为16进制字符串
* 使用默认缓存大小,见 {@link IoUtil#DEFAULT_BUFFER_SIZE} - * + * * @param data 被摘要数据 * @param bufferLength 缓存长度,不足1使用 {@link IoUtil#DEFAULT_BUFFER_SIZE} 做为默认值 * @return 摘要 @@ -224,6 +225,20 @@ public class HMac implements Serializable { return HexUtil.encodeHexStr(digest(data, bufferLength)); } + /** + * 验证生成的摘要与给定的摘要比较是否一致
+ * 简单比较每个byte位是否相同 + * + * @param digest 生成的摘要 + * @param digestToCompare 需要比较的摘要 + * @return 是否一致 + * @since 5.6.8 + * @see MessageDigest#isEqual(byte[], byte[]) + */ + public boolean verify(byte[] digest, byte[] digestToCompare){ + return MessageDigest.isEqual(digest, digestToCompare); + } + /** * 获取MAC算法块长度 * @return MAC算法块长度 diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java b/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java index 0a14e7bac..86020fddc 100644 --- a/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java +++ b/hutool-json/src/main/java/cn/hutool/json/jwt/Claims.java @@ -1,11 +1,9 @@ package cn.hutool.json.jwt; import cn.hutool.core.lang.Assert; -import cn.hutool.json.JSONUtil; +import cn.hutool.json.JSONObject; import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; /** * Claims 认证 @@ -15,14 +13,14 @@ import java.util.Map; public class Claims implements Serializable { private static final long serialVersionUID = 1L; - private final Map claimMap; + private final JSONObject claimJSON; public Claims() { - this.claimMap = new HashMap<>(); + this.claimJSON = new JSONObject(); } /** - * 增加Claims属性 + * 增加Claims属性,如果属性值为{@code null},则移除这个属性 * * @param name 属性名 * @param value 属性值 @@ -30,19 +28,10 @@ public class Claims implements Serializable { protected void setClaim(String name, Object value) { Assert.notNull(name, "Name must be not null!"); if (value == null) { - claimMap.remove(name); + claimJSON.remove(name); return; } - claimMap.put(name, value); - } - - /** - * 获取Claims数据Map - * - * @return map - */ - protected Map getClaimMap() { - return this.claimMap; + claimJSON.set(name, value); } /** @@ -51,6 +40,6 @@ public class Claims implements Serializable { * @return JSON字符串 */ public String getClaimsJson() { - return JSONUtil.toJsonStr(getClaimMap()); + return this.claimJSON.toString(); } } diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/JWT.java b/hutool-json/src/main/java/cn/hutool/json/jwt/JWT.java index ef7281c84..d7090b58f 100644 --- a/hutool-json/src/main/java/cn/hutool/json/jwt/JWT.java +++ b/hutool-json/src/main/java/cn/hutool/json/jwt/JWT.java @@ -1,13 +1,15 @@ package cn.hutool.json.jwt; import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.jwt.signers.JWTSigner; import java.nio.charset.Charset; /** * JSON Web Token (JWT),基于JSON的开放标准((RFC 7519)用于在网络应用环境间传递声明。
- * + *

* 结构:xxxxx.yyyyy.zzzzz *

    *
  • header:主要声明了JWT的签名算法
  • @@ -23,14 +25,41 @@ import java.nio.charset.Charset; */ public class JWT { - private Charset charset; - private Signer signer; private final JWTHeader header; private final JWTPayload payload; + private Charset charset; + private JWTSigner signer; + + /** + * 构造 + */ public JWT() { this.header = new JWTHeader(); this.payload = new JWTPayload(); + this.charset = CharsetUtil.CHARSET_UTF_8; + } + + /** + * 设置编码 + * + * @param charset 编码 + * @return this + */ + public JWT setCharset(Charset charset) { + this.charset = charset; + return this; + } + + /** + * 设置签名算法 + * + * @param signer 签名算法 + * @return this + */ + public JWT setSigner(JWTSigner signer) { + this.signer = signer; + return this; } /** @@ -38,7 +67,7 @@ public class JWT { * * @return JWT字符串 */ - public String sign(){ + public String sign() { final String headerBase64 = Base64.encodeUrlSafe(this.header.getClaimsJson(), charset); final String payloadBase64 = Base64.encodeUrlSafe(this.payload.getClaimsJson(), charset); final String sign = signer.sign(headerBase64, payloadBase64); diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/JWTHeader.java b/hutool-json/src/main/java/cn/hutool/json/jwt/JWTHeader.java index c9c3bdfc6..7cda2fa24 100644 --- a/hutool-json/src/main/java/cn/hutool/json/jwt/JWTHeader.java +++ b/hutool-json/src/main/java/cn/hutool/json/jwt/JWTHeader.java @@ -34,7 +34,7 @@ public class JWTHeader extends Claims { * @param keyId kid * @return this */ - public JWTHeader addKeyId(String keyId) { + public JWTHeader setKeyId(String keyId) { setClaim(KEY_ID, keyId); return this; } diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/Signer.java b/hutool-json/src/main/java/cn/hutool/json/jwt/Signer.java deleted file mode 100644 index 3fca58163..000000000 --- a/hutool-json/src/main/java/cn/hutool/json/jwt/Signer.java +++ /dev/null @@ -1,6 +0,0 @@ -package cn.hutool.json.jwt; - -public interface Signer { - - String sign(String header, String payload); -} diff --git a/hutool-json/src/main/java/cn/hutool/json/jwt/signers/JWTSigner.java b/hutool-json/src/main/java/cn/hutool/json/jwt/signers/JWTSigner.java new file mode 100644 index 000000000..52770ab6e --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/jwt/signers/JWTSigner.java @@ -0,0 +1,17 @@ +package cn.hutool.json.jwt.signers; + +/** + * JWT签名接口封装,通过实现此接口,完成不同算法的签名功能 + * + * @author looly + */ +public interface JWTSigner { + + /** + * 签名 + * @param header JWT头的JSON字符串 + * @param payload JWT载荷的JSON字符串 + * @return 签名结果,即JWT的第三部分 + */ + String sign(String header, String payload); +} diff --git a/hutool-jwt/pom.xml b/hutool-jwt/pom.xml new file mode 100644 index 000000000..818806ec9 --- /dev/null +++ b/hutool-jwt/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + jar + + + cn.hutool + hutool-parent + 5.6.8-SNAPSHOT + + + hutool-jwt + ${project.artifactId} + Hutool JWT生成、解析和验证实现 + + + + cn.hutool + hutool-json + ${project.parent.version} + + + cn.hutool + hutool-crypto + ${project.parent.version} + + + diff --git a/pom.xml b/pom.xml index 66b06fc80..352894849 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,7 @@ hutool-poi hutool-captcha hutool-socket + hutool-jwt