mirror of
https://gitee.com/dromara/hutool.git
synced 2025-05-08 06:37:58 +08:00
fix jwt bug
This commit is contained in:
parent
7ead906910
commit
86d711cc03
@ -14,6 +14,7 @@
|
|||||||
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误(issue#I3VTQW@Gitee)
|
* 【db 】 修复Oracle下别名错误造成的SQL语法啊错误(issue#I3VTQW@Gitee)
|
||||||
* 【core 】 修复ConcurrencyTester重复使用时开始测试未清空之前任务的问题(issue#I3VSDO@Gitee)
|
* 【core 】 修复ConcurrencyTester重复使用时开始测试未清空之前任务的问题(issue#I3VSDO@Gitee)
|
||||||
* 【poi 】 修复使用BigWriter写出,ExcelWriter修改单元格值失败的问题(issue#I3VSDO@Gitee)
|
* 【poi 】 修复使用BigWriter写出,ExcelWriter修改单元格值失败的问题(issue#I3VSDO@Gitee)
|
||||||
|
* 【jwt 】 修复Hmac算法下生成签名是hex的问题
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -199,6 +199,20 @@ public class Base64 {
|
|||||||
return Base64Encoder.encodeUrlSafe(FileUtil.readBytes(file));
|
return Base64Encoder.encodeUrlSafe(FileUtil.readBytes(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码为Base64字符串<br>
|
||||||
|
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
||||||
|
*
|
||||||
|
* @param arr 被编码的数组
|
||||||
|
* @param isMultiLine 在76个char之后是CRLF还是EOF
|
||||||
|
* @param isUrlSafe 是否使用URL安全字符,一般为{@code false}
|
||||||
|
* @return 编码后的bytes
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static String encodeStr(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {
|
||||||
|
return Base64Encoder.encodeStr(arr, isMultiLine, isUrlSafe);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编码为Base64<br>
|
* 编码为Base64<br>
|
||||||
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
||||||
|
@ -126,6 +126,20 @@ public class Base64Encoder {
|
|||||||
return StrUtil.str(encodeUrlSafe(source, false), DEFAULT_CHARSET);
|
return StrUtil.str(encodeUrlSafe(source, false), DEFAULT_CHARSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码为Base64字符串<br>
|
||||||
|
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
||||||
|
*
|
||||||
|
* @param arr 被编码的数组
|
||||||
|
* @param isMultiLine 在76个char之后是CRLF还是EOF
|
||||||
|
* @param isUrlSafe 是否使用URL安全字符,在URL Safe模式下,=为URL中的关键字符,不需要补充。空余的byte位要去掉,一般为{@code false}
|
||||||
|
* @return 编码后的bytes
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static String encodeStr(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {
|
||||||
|
return StrUtil.str(encode(arr, isMultiLine, isUrlSafe), DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编码为Base64<br>
|
* 编码为Base64<br>
|
||||||
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
* 如果isMultiLine为{@code true},则每76个字符一个换行符,否则在一行显示
|
||||||
|
@ -40,6 +40,16 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
|||||||
treeNodeConfig, TreeNodeConfig.DEFAULT_CONFIG);
|
treeNodeConfig, TreeNodeConfig.DEFAULT_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点配置
|
||||||
|
*
|
||||||
|
* @return 节点配置
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public TreeNodeConfig getConfig() {
|
||||||
|
return this.treeNodeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取父节点
|
* 获取父节点
|
||||||
*
|
*
|
||||||
@ -207,6 +217,7 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印
|
* 打印
|
||||||
|
*
|
||||||
* @param tree 树
|
* @param tree 树
|
||||||
* @param writer Writer
|
* @param writer Writer
|
||||||
* @param intent 缩进量
|
* @param intent 缩进量
|
||||||
|
@ -77,6 +77,28 @@ public class TreeUtil {
|
|||||||
return build(map, rootId);
|
return build(map, rootId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单点树构建,按照权重排序
|
||||||
|
*
|
||||||
|
* @param <E> ID类型
|
||||||
|
* @param map 源数据Map
|
||||||
|
* @param rootId 根节点id值 一般为 0 之类
|
||||||
|
* @return {@link Tree}
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public static <E> Tree<E> buildSingle(Map<E, Tree<E>> map, E rootId) {
|
||||||
|
final List<Tree<E>> list = build(map, rootId);
|
||||||
|
if (CollUtil.isNotEmpty(list)) {
|
||||||
|
final TreeNodeConfig config = list.get(0).getConfig();
|
||||||
|
final Tree<E> root = new Tree<>(config);
|
||||||
|
root.setId(rootId);
|
||||||
|
root.setChildren(list);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tree<E>(null).setId(rootId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树构建,按照权重排序
|
* 树构建,按照权重排序
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.crypto.digest;
|
package cn.hutool.crypto.digest;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
@ -25,8 +26,8 @@ import java.security.MessageDigest;
|
|||||||
* 一般的,消息鉴别码用于验证传输于两个共 同享有一个密钥的单位之间的消息。<br>
|
* 一般的,消息鉴别码用于验证传输于两个共 同享有一个密钥的单位之间的消息。<br>
|
||||||
* HMAC 可以与任何迭代散列函数捆绑使用。MD5 和 SHA-1 就是这种散列函数。HMAC 还可以使用一个用于计算和确认消息鉴别值的密钥。<br>
|
* HMAC 可以与任何迭代散列函数捆绑使用。MD5 和 SHA-1 就是这种散列函数。HMAC 还可以使用一个用于计算和确认消息鉴别值的密钥。<br>
|
||||||
* 注意:此对象实例化后为非线程安全!
|
* 注意:此对象实例化后为非线程安全!
|
||||||
* @author Looly
|
|
||||||
*
|
*
|
||||||
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class HMac implements Serializable {
|
public class HMac implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -34,8 +35,10 @@ public class HMac implements Serializable {
|
|||||||
private final MacEngine engine;
|
private final MacEngine engine;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- Constructor start
|
// ------------------------------------------------------------------------------------------- Constructor start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造,自动生成密钥
|
* 构造,自动生成密钥
|
||||||
|
*
|
||||||
* @param algorithm 算法 {@link HmacAlgorithm}
|
* @param algorithm 算法 {@link HmacAlgorithm}
|
||||||
*/
|
*/
|
||||||
public HMac(HmacAlgorithm algorithm) {
|
public HMac(HmacAlgorithm algorithm) {
|
||||||
@ -44,6 +47,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
|
*
|
||||||
* @param algorithm 算法 {@link HmacAlgorithm}
|
* @param algorithm 算法 {@link HmacAlgorithm}
|
||||||
* @param key 密钥
|
* @param key 密钥
|
||||||
*/
|
*/
|
||||||
@ -53,6 +57,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
|
*
|
||||||
* @param algorithm 算法 {@link HmacAlgorithm}
|
* @param algorithm 算法 {@link HmacAlgorithm}
|
||||||
* @param key 密钥
|
* @param key 密钥
|
||||||
*/
|
*/
|
||||||
@ -62,6 +67,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
|
*
|
||||||
* @param algorithm 算法
|
* @param algorithm 算法
|
||||||
* @param key 密钥
|
* @param key 密钥
|
||||||
* @since 4.5.13
|
* @since 4.5.13
|
||||||
@ -72,6 +78,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
|
*
|
||||||
* @param algorithm 算法
|
* @param algorithm 算法
|
||||||
* @param key 密钥
|
* @param key 密钥
|
||||||
* @since 4.5.13
|
* @since 4.5.13
|
||||||
@ -82,6 +89,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
|
*
|
||||||
* @param engine MAC算法实现引擎
|
* @param engine MAC算法实现引擎
|
||||||
* @since 4.5.13
|
* @since 4.5.13
|
||||||
*/
|
*/
|
||||||
@ -100,6 +108,7 @@ public class HMac implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------- Digest
|
// ------------------------------------------------------------------------------------------- Digest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成文件摘要
|
* 生成文件摘要
|
||||||
*
|
*
|
||||||
@ -121,6 +130,27 @@ public class HMac implements Serializable {
|
|||||||
return digest(data, CharsetUtil.CHARSET_UTF_8);
|
return digest(data, CharsetUtil.CHARSET_UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成文件摘要,并转为Base64
|
||||||
|
*
|
||||||
|
* @param data 被摘要数据
|
||||||
|
* @return 摘要
|
||||||
|
*/
|
||||||
|
public String digestBase64(String data, boolean isUrlSafe) {
|
||||||
|
return digestBase64(data, CharsetUtil.CHARSET_UTF_8, isUrlSafe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成文件摘要,并转为Base64
|
||||||
|
*
|
||||||
|
* @param data 被摘要数据
|
||||||
|
* @param charset 编码
|
||||||
|
* @return 摘要
|
||||||
|
*/
|
||||||
|
public String digestBase64(String data, Charset charset, boolean isUrlSafe) {
|
||||||
|
return Base64.encodeStr(digest(data, charset), false, isUrlSafe);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成文件摘要,并转为16进制字符串
|
* 生成文件摘要,并转为16进制字符串
|
||||||
*
|
*
|
||||||
@ -242,8 +272,8 @@ public class HMac implements Serializable {
|
|||||||
* @param digest 生成的摘要
|
* @param digest 生成的摘要
|
||||||
* @param digestToCompare 需要比较的摘要
|
* @param digestToCompare 需要比较的摘要
|
||||||
* @return 是否一致
|
* @return 是否一致
|
||||||
* @since 5.6.8
|
|
||||||
* @see MessageDigest#isEqual(byte[], byte[])
|
* @see MessageDigest#isEqual(byte[], byte[])
|
||||||
|
* @since 5.6.8
|
||||||
*/
|
*/
|
||||||
public boolean verify(byte[] digest, byte[] digestToCompare) {
|
public boolean verify(byte[] digest, byte[] digestToCompare) {
|
||||||
return MessageDigest.isEqual(digest, digestToCompare);
|
return MessageDigest.isEqual(digest, digestToCompare);
|
||||||
@ -251,6 +281,7 @@ public class HMac implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取MAC算法块长度
|
* 获取MAC算法块长度
|
||||||
|
*
|
||||||
* @return MAC算法块长度
|
* @return MAC算法块长度
|
||||||
* @since 5.3.3
|
* @since 5.3.3
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +12,8 @@ import cn.hutool.jwt.signers.JWTSigner;
|
|||||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyPair;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -125,6 +127,30 @@ public class JWT {
|
|||||||
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
|
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置签名算法
|
||||||
|
*
|
||||||
|
* @param algorithmId 签名算法ID,如HS256
|
||||||
|
* @param key 密钥
|
||||||
|
* @return this
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public JWT setSigner(String algorithmId, Key key) {
|
||||||
|
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置非对称签名算法
|
||||||
|
*
|
||||||
|
* @param algorithmId 签名算法ID,如HS256
|
||||||
|
* @param keyPair 密钥对
|
||||||
|
* @return this
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public JWT setSigner(String algorithmId, KeyPair keyPair) {
|
||||||
|
return setSigner(JWTSignerUtil.createSigner(algorithmId, keyPair));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置签名算法
|
* 设置签名算法
|
||||||
*
|
*
|
||||||
|
@ -51,7 +51,7 @@ public class HMacJWTSigner implements JWTSigner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sign(String headerBase64, String payloadBase64) {
|
public String sign(String headerBase64, String payloadBase64) {
|
||||||
return hMac.digestHex(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset);
|
return hMac.digestBase64(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -12,7 +12,7 @@ public interface JWTSigner {
|
|||||||
*
|
*
|
||||||
* @param headerBase64 JWT头的JSON字符串的Base64表示
|
* @param headerBase64 JWT头的JSON字符串的Base64表示
|
||||||
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
|
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
|
||||||
* @return 签名结果,即JWT的第三部分
|
* @return 签名结果Base64,即JWT的第三部分
|
||||||
*/
|
*/
|
||||||
String sign(String headerBase64, String payloadBase64);
|
String sign(String headerBase64, String payloadBase64);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.jwt;
|
package cn.hutool.jwt;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -73,4 +74,14 @@ public class JWTTest {
|
|||||||
|
|
||||||
jwt.sign();
|
jwt.sign();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verifyTest(){
|
||||||
|
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
|
||||||
|
"eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MjQwMDQ4MjIsInVzZXJJZCI6MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV_op5LoibLkuozlj7ciLCJzeXNfbWVudV8xIiwiUk9MRV_op5LoibLkuIDlj7ciLCJzeXNfbWVudV8yIl0sImp0aSI6ImQ0YzVlYjgwLTA5ZTctNGU0ZC1hZTg3LTVkNGI5M2FhNmFiNiIsImNsaWVudF9pZCI6ImhhbmR5LXNob3AifQ." +
|
||||||
|
"aixF1eKlAKS_k3ynFnStE7-IRGiD5YaqznvK2xEjBew";
|
||||||
|
|
||||||
|
final boolean verify = JWT.of(token).setKey(StrUtil.utf8Bytes("123456")).verify();
|
||||||
|
Assert.assertTrue(verify);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user