阅读量:0
一,签名算法-官网
copy官网
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; } }
调用
HttpHeaders headers = tencentCloudAPITC3Demo.buildHeader(req); ResponseEntity<String> stringResponseEntity = restTemplateUtils.serviceApiInvoke(req, tencentOcrUrl, headers);
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
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
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
{ "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,算法代码
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?不知道!
三,签名算法-腾讯运维提供
调用
String req = JSON.toJSONString(tncOrcReqDTO); HashMap<String, String> authorizationHearderV3 = SingtrueUtil.getAuthorizationHearderV3(req); String bizTokenKey = SingtrueUtil.getBizTokenKey(authorizationHearderV3, req);
算法
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(); } }