一,签名算法-官网
copy官网
java
package com.smcv.customer.service.util;
import org.springframework.http.HttpHeaders;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.TreeMap;
public class TencentCloudAPITC3Demo {
private final static Charset UTF8 = StandardCharsets.UTF_8;
// 需要设置环境变量 TENCENTCLOUD_SECRET_ID,值为示例的 AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******
// private final static String SECRET_ID = System.getenv("TENCENTCLOUD_SECRET_ID");
private final static String SECRET_ID = "AKIDBE4g3B4";
// 需要设置环境变量 TENCENTCLOUD_SECRET_KEY,值为示例的 Gu5t9xGARNpq86cd98joQYCN3*******
// private final static String SECRET_KEY = System.getenv("TENCENTCLOUD_SECRET_KEY");
private final static String SECRET_KEY = "tWt2uXu1uc";
private final static String CT_JSON = "application/json; charset=utf-8";
public static byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(UTF8));
}
public static String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(UTF8));
return DatatypeConverter.printHexBinary(d).toLowerCase();
}
public static void main(String[] args) throws Exception {
String service = "cvm";
String host = "cvm.tencentcloudapi.com";
// String region = "ap-guangzhou";
// String action = "DescribeInstances";
String region = "ap-shanghai";
String action = "SmartStructuralOCRV2";
String version = "2018-11-19";
String algorithm = "TC3-HMAC-SHA256";
// String timestamp = "1551113065";
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
String signedHeaders = "content-type;host;x-tc-action";
String payload = "{\"Limit\": 1, \"Filters\": [{\"Values\": [\"\\u672a\\u547d\\u540d\"], \"Name\": \"instance-name\"}]}";
String hashedRequestPayload = sha256Hex(payload);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
TreeMap<String, String> headers = new TreeMap<String, String>();
headers.put("Authorization", authorization);
headers.put("Content-Type", CT_JSON);
headers.put("Host", host);
headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", timestamp);
headers.put("X-TC-Version", version);
headers.put("X-TC-Region", region);
StringBuilder sb = new StringBuilder();
sb.append("curl -X POST https://").append(host).append(" -H \"Authorization: ").append(authorization).append("\"").append(" -H \"Content-Type: application/json; charset=utf-8\"").append(" -H \"Host: ").append(host).append("\"").append(" -H \"X-TC-Action: ").append(action).append("\"").append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"").append(" -H \"X-TC-Version: ").append(version).append("\"").append(" -H \"X-TC-Region: ").append(region).append("\"").append(" -d '").append(payload).append("'");
System.out.println(sb.toString());
}
public static HttpHeaders buildHeader(String payload) throws Exception {
String service = "ocr";
String host = "ocr.tencentcloudapi.com";
String region = "ap-shanghai";
String action = "SmartStructuralOCRV2";
String version = "2018-11-19";
String algorithm = "TC3-HMAC-SHA256";
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
String signedHeaders = "content-type;host;x-tc-action";
// String payload = "{\"Limit\": 1, \"Filters\": [{\"Values\": [\"\\u672a\\u547d\\u540d\"], \"Name\": \"instance-name\"}]}";
String hashedRequestPayload = sha256Hex(payload);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", " + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", authorization);
httpHeaders.add("Content-Type", CT_JSON);
httpHeaders.add("Host", host);
httpHeaders.add("X-TC-Action", action);
httpHeaders.add("X-TC-Timestamp", timestamp);
httpHeaders.add("X-TC-Version", version);
httpHeaders.add("X-TC-Region", region);
StringBuilder sb = new StringBuilder();
sb.append("curl -X POST https://").append(host).append(" -H \"Authorization: ").append(authorization).append("\"").append(" -H \"Content-Type: application/json; charset=utf-8\"").append(" -H \"Host: ").append(host).append("\"").append(" -H \"X-TC-Action: ").append(action).append("\"").append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"").append(" -H \"X-TC-Version: ").append(version).append("\"").append(" -H \"X-TC-Region: ").append(region).append("\"").append(" -d '").append(payload).append("'");
System.out.println(sb.toString());
return httpHeaders;
}
}
调用
java
HttpHeaders headers = tencentCloudAPITC3Demo.buildHeader(req);
ResponseEntity<String> stringResponseEntity = restTemplateUtils.serviceApiInvoke(req, tencentOcrUrl, headers);
java
public ResponseEntity<String> serviceApiInvoke(String requestBody, String url, HttpHeaders headers) {
// 创建 HttpEntity 对象,用于设置请求体和请求头
HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
// 发送 POST 请求并获取响应
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
// 输出响应结果
return response;
}
响应乱码问题
方案1
java
public ResponseEntity<String> serviceApiInvoke(String requestBody, String url, HttpHeaders headers) {
// 创建 HttpEntity 对象,用于设置请求体和请求头
HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) messageConverter).setDefaultCharset(Charset.forName("UTF-8"));
}
}
// 发送 POST 请求并获取响应
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
// 输出响应结果
return response;
}
方案2
java
public String serviceApiInvokeUtf8(String requestBody, String url, HttpHeaders headers) {
// HttpHeaders httpHeaders = new HttpHeaders();
// 可以设置一些参数
HttpEntity httpEntity = new HttpEntity(requestBody,headers);
ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, byte[].class);
try {
String result = new String(exchange.getBody(), "UTF-8");
return result;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
二,签名算法-自定义
据说也是copy官网
1,签名失败问题
背景,生产上已经跑了很长一段时间,突然有一天接口突然调不通了(什么都没动的情况下,很奇异),报错如下
2,响应报错信息
签名失败
AuthFailure.SignatureFailure
java
{
"body": "{\"Response\":{\"Error\":{\"Code\":\"AuthFailure.SignatureFailure\",\"Message\":\"请æ±ç¾åéªè¯å¤±è´¥ï¼è¯·æ£æ¥æ¨çç¾å计ç®æ¯å¦æ£ç¡®ã\"},\"RequestId\":\"ebcf25f4-ee15-4286-8366-7352414e69e4\"}}",
"headers": {
"Date": [
"Thu, 01 Aug 2024 01:29:49 GMT"
],
"Content-Type": [
"application/json"
],
"Content-Length": [
"195"
],
"Connection": [
"keep-alive"
]
},
"statusCode": 4,
"statusCodeValue": 200
}
3,算法代码
java
package com.smcv.customer.service.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
@Slf4j
public class PdfUtils {
// FailedOperation.DownLoadError 文件下载失败。
// FailedOperation.ImageDecodeFailed 图片解码失败。
// FailedOperation.OcrFailed OCR识别失败。
// FailedOperation.UnKnowError 未知错误。
// FailedOperation.UnOpenError 服务未开通。
// InvalidParameterValue.InvalidParameterValueLimit 参数值错误。
// LimitExceeded.TooLargeFileError 文件内容太大。
// ResourcesSoldOut.ChargeStatusException 计费状态异常
private final static Charset UTF8 = StandardCharsets.UTF_8;
// 需要设置环境变量 TENCENTCLOUD_SECRET_ID,值为示例的 AKIDz8krbsJ5**********mLPx3EXAMPL
private final static String SECRET_ID = "";
// 需要设置环境变量 TENCENTCLOUD_SECRET_KEY,值为示例的 Gu5t9xGAR***********EXAMPLE
private final static String SECRET_KEY = "";
private final static String CT_JSON = "application/json";
public static byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(UTF8));
}
public static String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(UTF8));
return DatatypeConverter.printHexBinary(d).toLowerCase();
}
public static HttpHeaders getTncOrc(String payload) throws Exception {
String service = "ocr";
String host = "ocr.tencentcloudapi.com";
String region = "ap-shanghai";
String action = "SmartStructuralOCRV2";
String tag = "cdf41db8-29e9-11ee-9ed1-5254005e545b";
String version = "2018-11-19";
String algorithm = "TC3-HMAC-SHA256";
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
//String timestamp = "1689760798";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.parseLong(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
String signedHeaders = "content-type;host;x-tc-action";
String hashedRequestPayload = sha256Hex(payload);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
// ************* 步骤 4:拼接 Authorization *************
String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", authorization);
headers.add("Content-Type", CT_JSON);
headers.add("Host", host);
headers.add("X-TC-Action", action);
headers.add("X-TC-Timestamp", timestamp);
headers.add("X-TC-Version", version);
headers.add("X-TC-Region", region);
headers.add("X-TC-Language", "zh-CN");
//
// StringBuilder sb = new StringBuilder();
// sb.append("curl -X POST https://").append(host)
// .append(" -H \"Authorization: ").append(authorization).append("\"")
// .append(" -H \"Content-Type: ").append(CT_JSON).append("\"")
// .append(" -H \"Host: ").append(host).append("\"")
// .append(" -H \"X-TC-Action: ").append(action).append("\"")
// .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"")
// .append(" -H \"X-TC-Version: ").append(version).append("\"")
// .append(" -H \"X-TC-Region: ").append(region).append("\"")
// .append(" -H \"X-TC-Language: ").append("zh-CN").append("\"")
// .append(" -d '").append(payload).append("'");
// log.info(sb.toString());
return headers;
}
}
4,原因
对比官网签名算法,主要区别在于编码方式
处理方案:替换以下内容,接口正常了。改回老的还是签名失败(交叉对比确认,肯定是签名失败了)
private final static String CT_JSON = "application/json";
private final static String CT_JSON = "application/json; charset=utf-8";
String canonicalHeaders = "content-type:application/json\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n" + "x-tc-action:" + action.toLowerCase() + "\n";
5,又突然好了
上面第四点还是用老的,不写charset=utf-8,tmd接口又正常了,why?不知道!
三,签名算法-腾讯运维提供
调用
java
String req = JSON.toJSONString(tncOrcReqDTO);
HashMap<String, String> authorizationHearderV3 = SingtrueUtil.getAuthorizationHearderV3(req);
String bizTokenKey = SingtrueUtil.getBizTokenKey(authorizationHearderV3, req);
算法
java
package com.smcv.customer.service.util;
import org.springframework.http.HttpHeaders;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class SingtrueUtil {
private static final String TAG = "SigtrueUtil";
private final static String ALGORITHM = "TC3-HMAC-SHA256"; // TC3-HMAC-SHA256:签名方法,目前固定取该值;
private static final Charset UTF8 = StandardCharsets.UTF_8;
private final static String CT_JSON = "application/json; charset=utf-8";
private static String action = "SmartStructuralOCRV2";
private static String urlStr = "https://ocr.tencentcloudapi.com";
private static String service = "ocr";
private static String version = "2018-11-19";
private static String region = "ap-shanghai";
private static String tempToken = null;
private final static String host = "ocr.tencentcloudapi.com";
private final static String secretId = "";
private final static String secretKey = "";
/**
* 腾讯云签名
*
* @param bodyParam body参数
* @param service 服务名
* @param secretId secretId
* @param secretKey secretKey
* @param tempToken 临时证书所用的 Token ,需要结合临时密钥一起使用。临时密钥和 Token
* 需要到访问管理服务调用接口获取。长期密钥不需要 Token。
* @param action 接口名称
* @param version 版本号
* @param region 区域
* @return headers 请求头
* @throws Exception e
*/
public static HashMap<String, String> getAuthorizationHearder(
String host,
String bodyParam,
String service,
String secretId,
String secretKey,
String tempToken,
String action,
String version,
String region) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);// 当前 UNIX 时间戳,可记录发起 API
// 请求的时间。注意:如果与服务器时间相差超过5分钟,会引起签名过期错误
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
String signedHeaders = "content-type;host";
String hashedRequestPayload = sha256Hex(bodyParam);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = bytesToHexFun(hmac256(secretSigning, stringToSign));// DatatypeConverter.printHexBinary(hmac256(secretSigning,
// stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = ALGORITHM + " " + "Credential=" + secretId + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
HashMap<String, String> headers = new HashMap<>();
if (tempToken != null && !tempToken.isEmpty()) {
headers.put("X-TC-Token", tempToken);
}
headers.put("Authorization", authorization);
headers.put("Content-Type", CT_JSON);
headers.put("Host", host);
headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", timestamp);
headers.put("X-TC-Version", version);
headers.put("X-TC-Region", region);
StringBuilder sb = new StringBuilder();
sb.append("curl -X POST https://").append(host).append(" -H \"Authorization: ").append(authorization)
.append("\"").append(" -H \"Content-Type: application/json; charset=utf-8\"").append(" -H \"Host: ")
.append(host).append("\"").append(" -H \"X-TC-Action: ").append(action).append("\"")
.append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"").append(" -H \"X-TC-Version: ")
.append(version).append("\"").append(" -H \"X-TC-Region: ").append(region).append("\"").append(" -d '")
.append(bodyParam).append("'");
System.out.println(sb);
return headers;
}
public static HashMap<String, String> getAuthorizationHearderV3(String bodyParam) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);// 当前 UNIX 时间戳,可记录发起 API
// 请求的时间。注意:如果与服务器时间相差超过5分钟,会引起签名过期错误
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
String signedHeaders = "content-type;host";
String hashedRequestPayload = sha256Hex(bodyParam);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = bytesToHexFun(hmac256(secretSigning, stringToSign));// DatatypeConverter.printHexBinary(hmac256(secretSigning,
// stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = ALGORITHM + " " + "Credential=" + secretId + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
HashMap<String, String> headers = new HashMap<>();
if (tempToken != null && !tempToken.isEmpty()) {
headers.put("X-TC-Token", tempToken);
}
headers.put("Authorization", authorization);
headers.put("Content-Type", CT_JSON);
headers.put("Host", host);
headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", timestamp);
headers.put("X-TC-Version", version);
headers.put("X-TC-Region", region);
;
// StringBuilder sb = new StringBuilder();
// sb.append("curl -X POST https://").append(host).append(" -H \"Authorization: ").append(authorization)
// .append("\"").append(" -H \"Content-Type: application/json; charset=utf-8\"").append(" -H \"Host: ")
// .append(host).append("\"").append(" -H \"X-TC-Action: ").append(action).append("\"")
// .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"").append(" -H \"X-TC-Version: ")
// .append(version).append("\"").append(" -H \"X-TC-Region: ").append(region).append("\"").append(" -d '")
// .append(bodyParam).append("'");
// System.out.println(sb);
return headers;
}
public static HttpHeaders getAuthorizationHearderV2(String bodyParam) throws Exception {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);// 当前 UNIX 时间戳,可记录发起 API
// 请求的时间。注意:如果与服务器时间相差超过5分钟,会引起签名过期错误
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
String signedHeaders = "content-type;host";
String hashedRequestPayload = sha256Hex(bodyParam);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = bytesToHexFun(hmac256(secretSigning, stringToSign));// DatatypeConverter.printHexBinary(hmac256(secretSigning,
// stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = ALGORITHM + " " + "Credential=" + secretId + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", authorization);
headers.add("Content-Type", CT_JSON);
headers.add("Host", host);
headers.add("X-TC-Action", action);
headers.add("X-TC-Timestamp", timestamp);
headers.add("X-TC-Version", version);
headers.add("X-TC-Region", region);
headers.add("X-TC-Language", "zh-CN");
// StringBuilder sb = new StringBuilder();
// sb.append("curl -X POST https://").append(host).append(" -H \"Authorization: ").append(authorization)
// .append("\"").append(" -H \"Content-Type: application/json; charset=utf-8\"").append(" -H \"Host: ")
// .append(host).append("\"").append(" -H \"X-TC-Action: ").append(action).append("\"")
// .append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"").append(" -H \"X-TC-Version: ")
// .append(version).append("\"").append(" -H \"X-TC-Region: ").append(region).append("\"").append(" -d '")
// .append(bodyParam).append("'");
// System.out.println(sb);
return headers;
}
public static String getBizTokenKey(HashMap<String, String> headerMap, String bodyParam) throws IOException {
String resultString;
HttpURLConnection httpURLConnection = null;
try {
URL url = new URL(urlStr);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(6000);
httpURLConnection.setUseCaches(false);// 不使用缓存
httpURLConnection.setInstanceFollowRedirects(true);// 是成员变量 仅作用域当前函数,设置当前这个对象
httpURLConnection.setReadTimeout(3000);
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
}
// httpURLConnection.setRequestProperty();
httpURLConnection.connect();
// ---------------使用字节流发送数据---------------------------
OutputStream out = httpURLConnection.getOutputStream();
// 缓冲字节流 包装字节流
BufferedOutputStream bos = new BufferedOutputStream(out);
// 把字节流数组写入缓冲区中
bos.write(bodyParam.getBytes("UTF-8"));
// 刷新缓冲区 发送数据
bos.flush();
out.close();
bos.close();
// 如果响应码为200代表请求访问成功
if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream in = httpURLConnection.getInputStream();
resultString = getContent(in);
} else {
throw new RuntimeException("请求失败");
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("请求失败");
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return resultString;
}
/**
* inputStream转为String类型
*
* @param inputStream
* @return
*/
private static String getContent(InputStream inputStream) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = bufferedReader.readLine()) != null) {
sb.append(line + "/n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString().replace("/n", "");
}
private static byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(UTF8));
}
private static String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(UTF8));
return bytesToHexFun(d);// DatatypeConverter.printHexBinary(d).toLowerCase();
}
private static String bytesToHexFun(byte[] bytes) {
StringBuilder buf = new StringBuilder(bytes.length * 2);
for (byte b : bytes) { // 使用String的format方法进行转换
buf.append(String.format("%02x", b & 0xff));
}
return buf.toString();
}
}