parameters, String endpoint, String secretId, String secretKey) {
+ // 拼接规范请求串
+ String canonicalRequest = StrUtil.format("POST\n/\n\n{}\ncontent-type;host\n{}",
+ StrUtil.format("content-type:application/json; charset=utf-8\nhost:{}\n", endpoint),
+ sha256Hex(JSONUtil.toJsonStr(parameters)));
+
+ // 计算时间
+ String timestamp = String.valueOf(DateUtil.currentSeconds());
+ String date = DateUtil.format(new DateTime(TimeZone.getTimeZone("UTC")), "yyyy-MM-dd");
+ String credentialScope = StrUtil.format("{}/{}/tc3_request", date, endpoint.split("\\.")[0]);
+ String stringToSign = StrUtil.format("TC3-HMAC-SHA256\n{}\n{}\n{}",
+ timestamp, credentialScope,
+ sha256Hex(canonicalRequest));
+
+ // 计算签名
+ byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(StandardCharsets.UTF_8), date);
+ byte[] secretService = hmac256(secretDate, endpoint.split("\\.")[0]);
+ byte[] secretSigning = hmac256(secretService, "tc3_request");
+ String authorization = StrUtil.format("TC3-HMAC-SHA256 Credential={}/{}, SignedHeaders=content-type;host, Signature={}",
+ secretId, credentialScope,
+ DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase());
+
+ // 构建返回信息
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.set("signature", authorization);
+ jsonObject.set("timestamp", timestamp);
+ return jsonObject;
+ }
+
+ private static byte[] hmac256(byte[] key, String msg) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
+ mac.init(secretKeySpec);
+ return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static String sha256Hex(String s) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
+ return DatatypeConverter.printHexBinary(d).toLowerCase();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/AliYunSignatureTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/AliYunSignatureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f60bb5e449b9c83a7972a379afb257adc9ff274d
--- /dev/null
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/AliYunSignatureTest.java
@@ -0,0 +1,102 @@
+package cn.hutool.crypto.test;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Console;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.AliYunSignature;
+import cn.hutool.json.JSONObject;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.TreeMap;
+
+/**
+ * 阿里云API签名测试
+ * 获取ID、SECRET: https://ram.console.aliyun.com/manage/ak?spm=5176.12818093.nav-right.dak.488716d00nyfCh
+ * 2020-09-17 21:07
+ *
+ * @author Dan
+ **/
+public class AliYunSignatureTest {
+
+ /**
+ * 访问密钥ID 用于调用API
+ */
+ private static final String ACCESSKEY_ID = "";
+
+ /**
+ * 密钥
+ */
+ private static final String ACCESSKEY_SECRET = "";
+
+ /**
+ * 短信发送
+ */
+ @Test
+ public void sendSms() {
+ JSONObject templateParam = new JSONObject();
+ templateParam.set("code", "123456");
+ templateParam.set("time", "5");
+ // 构建请求参数
+ Map parameters = AliYunSignature.signatureParameterInitialization(ACCESSKEY_ID);
+ // 第二部分由业务API参数组成
+ parameters.put("Action", "SendSms");
+ parameters.put("Version", "2017-05-25");
+ parameters.put("RegionId", "cn-hangzhou");
+ parameters.put("PhoneNumbers", "+8613844444444");
+ parameters.put("SignName", "hutool");
+ parameters.put("TemplateCode", "SMS_199222222");
+ parameters.put("TemplateParam", templateParam.toString());
+ parameters.put("OutId", "");
+ parameters.put("SmsUpExtendCode", "");
+ Console.log(AliYunSignature.getAliYunSignature(parameters, ACCESSKEY_SECRET, "dysmsapi.aliyuncs.com"));
+ }
+
+ /**
+ * 获取云服务器信息
+ */
+ @Test
+ public void getEcs() {
+ Map parameters = new TreeMap() {{
+ // 第一部分由系统参数组成
+ put("SignatureMethod", "HMAC-SHA1");
+ put("SignatureNonce", IdUtil.objectId());
+ put("AccessKeyId", ACCESSKEY_ID);
+ put("SignatureVersion", "1.0");
+ put("Timestamp", DateUtil.format(new DateTime(TimeZone.getTimeZone("GMT+:08:00")), "yyyy-MM-dd'T'HH:mm:ss'Z'"));
+ put("Format", "json");
+ // 第二部分由业务API参数组成
+ put("Action", "DescribeInstances");
+ put("Version", "2014-05-26");
+ put("RegionId", "cn-hangzhou");
+ }};
+ Console.log(AliYunSignature.getAliYunSignature(parameters, ACCESSKEY_SECRET, "ecs.aliyuncs.com"));
+ }
+
+ /**
+ * 设置安全组
+ */
+ @Test
+ public void setSecurityGroup() {
+ Map parameters = new TreeMap() {{
+ // 第一部分由系统参数组成
+ put("SignatureMethod", "HMAC-SHA1");
+ put("SignatureNonce", IdUtil.objectId());
+ put("AccessKeyId", ACCESSKEY_ID);
+ put("SignatureVersion", "1.0");
+ put("Timestamp", DateUtil.format(new DateTime(TimeZone.getTimeZone("GMT+:08:00")), "yyyy-MM-dd'T'HH:mm:ss'Z'"));
+ put("Format", "json");
+ // 第二部分由业务API参数组成
+ put("Action", "AuthorizeSecurityGroup");
+ put("Version", "2014-05-26");
+ put("IpProtocol", "tcp");
+ put("PortRange","8000/9600");
+ put("RegionId","cn-hangzhou");
+ put("SecurityGroupId","sg-bp17zst8hsu4rpwy2l37");
+ put("SourceCidrIp","0.0.0.0/0");
+ }};
+ Console.log(AliYunSignature.getAliYunSignature(parameters, ACCESSKEY_SECRET, "ecs.aliyuncs.com"));
+ }
+}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/TencentCloudSignatureTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/TencentCloudSignatureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..db55047e2cda94d2101692447f6491ffe6fb2fe7
--- /dev/null
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/TencentCloudSignatureTest.java
@@ -0,0 +1,106 @@
+package cn.hutool.crypto.test;
+
+import cn.hutool.core.lang.Console;
+import cn.hutool.crypto.TencentCloudSignature;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 腾讯云API签名测试
+ * 2020-09-17 21:55
+ *
+ * @author Dan
+ **/
+public class TencentCloudSignatureTest {
+
+ /**
+ * 访问密钥ID 用于调用API
+ */
+ private static final String SECRET_ID = "";
+
+ /**
+ * 密钥
+ */
+ private static final String SECRET_KEY = "";
+
+ /**
+ * 短信发送
+ */
+ @Test
+ public void sendSms() {
+ // 需要发送的电话(需要+86)
+ JSONArray phoneNumberSet = new JSONArray();
+ phoneNumberSet.add("+8613844444444");
+ phoneNumberSet.add("+8613855555555");
+
+ // 模板参数
+ JSONArray templateParam = new JSONArray();
+ templateParam.add("123456");
+ templateParam.add("3");
+
+ // 构建请求参数
+ Map parameters = new HashMap(8) {{
+ put("PhoneNumberSet", phoneNumberSet);
+ put("TemplateID", "777777");
+ put("TemplateParamSet", templateParam);
+ put("SmsSdkAppid", "4444444444");
+ put("Sign", "hutool");
+ put("ExtendCode", "");
+ put("SessionContext", "");
+ put("SenderId", "");
+ }};
+
+ // 构建签名信息
+ JSONObject signature = TencentCloudSignature.getTencentCloudSignature(parameters, "sms.tencentcloudapi.com", SECRET_ID, SECRET_KEY);
+ Console.log(signature);
+
+ // 构建链式请求
+// String result = HttpRequest.post("https://sms.tencentcloudapi.com/")
+// .header("Content-Type", "application/json; charset=utf-8")
+// .header("Host", "sms.tencentcloudapi.com")
+// .header("Authorization", signature.getStr("signature"))
+// .header("X-TC-Action", "SendSms")
+// .header("X-TC-Timestamp", signature.getStr("timestamp"))
+// .header("X-TC-Version", "2019-07-11")
+// .header("X-TC-RequestClient", "SDK_JAVA_3.1.130")
+// .header("X-TC-Region", "")
+// .body(JSONUtil.toJsonStr(parameters).getBytes(StandardCharsets.UTF_8))
+// .timeout(-1).execute().body();
+// Console.log(result);
+ }
+
+ /**
+ * 获取云服务器信息
+ */
+ @Test
+ public void getCvm() {
+
+ // 构建请求参数
+ Map parameters = new HashMap(2) {{
+ // 不是必须参数
+ put("Offset",0);
+ put("Limit",20);
+ }};
+
+ // 构建签名信息
+ JSONObject signature = TencentCloudSignature.getTencentCloudSignature(parameters, "cvm.tencentcloudapi.com", SECRET_ID, SECRET_KEY);
+ Console.log(signature);
+
+// String result = HttpRequest.post("https://sms.tencentcloudapi.com/")
+// .header("Content-Type", "application/json; charset=utf-8")
+// .header("Host", "cvm.tencentcloudapi.com")
+// .header("Authorization", signature.getStr("signature"))
+// .header("X-TC-Action", "DescribeInstances")
+// .header("X-TC-Timestamp", signature.getStr("timestamp"))
+// .header("X-TC-Version", "2017-03-12")
+// .header("X-TC-RequestClient", "SDK_JAVA_3.1.130")
+// .header("X-TC-Region", "ap-shanghai")
+// .body(JSONUtil.toJsonStr(parameters).getBytes(StandardCharsets.UTF_8))
+// .timeout(-1).execute().body();
+// Console.log(result);
+ }
+}