腾讯云 API 会对每个请求进行身份验证,用户使用原生API接入需要使用安全凭证,经过特定的步骤对请求进行签名(Signature),每个请求都需要在公共参数中指定该签名结果并以指定的方式和格式发送请求,以下内容主要介绍 API 接口文档参数以及V3签名方法。
API文档
公共参数
公共参数是用于标识用户和接口签名的参数,API接口文档上不会展示公共参数说明,但每次请求API均需要携带这些参数,才能正常发起请求。
签名方法
腾讯云支持V1、V3两种签名方式,推荐使用V3签名方法计算签名,签名方法 v3 (有时也称作 TC3-HMAC-SHA256)相比签名方法 v1更安全,支持更大的请求包,支持 POST JSON 格式,性能有一定提升。首次接触,建议使用 API Explorer 中的“签名串生成”功能,选择签名版本为“API 3.0 签名 v3”,可以生成签名过程进行验证。
使用签名方法 v3 时,公共参数需要统一放到 HTTP Header 请求头部中,如下表所示:
参数名称 | 类型 | 必选 | 描述 |
Action | String | 是 | HTTP 请求头:X-TC-Action。操作的接口名称,该字段取值为 TextModeration。 |
Region | String | - | HTTP 请求头:X-TC-Region。地域参数,用来标识希望操作哪个地域的数据。取值参考接口文档中输入参数章节关于公共参数 Region 的说明。 注意:某些接口不需要传递该参数,接口文档中会对此特别说明,此时即使传递该参数也不会生效。 |
Timestamp | Integer | 是 | HTTP 请求头:X-TC-Timestamp。当前 UNIX 时间戳,可记录发起 API 请求的时间。例如 1529223702。 注意:如果与服务器时间相差超过5分钟,会引起签名过期错误。 |
Version | String | 是 | HTTP 请求头:X-TC-Version。操作的 API 的版本。取值参考接口文档中入参公共参数 Version 的说明。该字段取值为2020-12-29。 |
Authorization | String | 是 | HTTP 标准身份认证头部字段,例如:
TC3-HMAC-SHA256
Credential
=AKID****/Date/service/tc3_request,
SignedHeaders
=content-type
;host, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
其中,TC3-HMAC-SHA256:签名方法,目前固定取该值。 Credential:签名凭证,AKID**** 是 SecretId;Date 是 UTC 标准时间的日期,取值需要和公共参数 X-TC-Timestamp 换算的 UTC 标准时间日期一致;service 为具体产品名,通常为域名前缀,例如域名 cvm.tencentcloudapi.com 意味着产品名是 cvm。本产品取值为 tms;tc3_request 为固定字符串。 SignedHeaders:参与签名计算的头部信息,content-type 和 host 为必选头部。 Signature:签名摘要,计算过程请参见 签名版本 v3 签名过程。 |
Token | String | 否 | HTTP 请求头:X-TC-Token。即 安全凭证服务 所颁发的临时安全凭证中的 Token,使用时需要将 SecretId 和 SecretKey 的值替换为临时安全凭证中的 TmpSecretId 和 TmpSecretKey。使用长期密钥时不能设置此 Token 字段。 |
Language | String | 否 | HTTP 请求头:X-TC-Language。指定接口返回的语言,仅部分接口支持此参数。 取值:zh-CN,en-US。zh-CN 返回中文,en-US 返回英文。 |
云 API 支持 GET 和 POST 请求。
对于 GET 方法,只支持
Content-Type: application/x-www-form-urlencoded
协议格式。对于 POST 方法,目前支持
Content-Type: application/json
协议格式。示例代码
以下提供 Java、Go、Python 示例 demo,填写密钥信息、接口入参即可调用。其他语言请参考签名方法 V3-签名演示,签名演示是云服务器服务作为示例,实际调用时需要根据 API 接口文档填写参数。
import java.nio.charset.Charset;import java.io.OutputStream;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;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;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import javax.xml.bind.DatatypeConverter;public class TextModeration {private final static Charset UTF8 = StandardCharsets.UTF_8;private final static String SECRET_ID = "";private final static String SECRET_KEY = "";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 = "tms";String host = "tms.tencentcloudapi.com";String region = "ap-guangzhou";String action = "TextModeration";String version = "2020-12-29";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")));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 = "{\\"Content\\": \\"xxxx\\",\\"BizType\\": \\"xxxx\\"}";// body数据为jsonString hashedRequestPayload = sha256Hex(payload);String canonicalRequest = httpRequestMethod + "\\n" + canonicalUri + "\\n" + canonicalQueryString + "\\n"+ canonicalHeaders + "\\n" + signedHeaders + "\\n" + hashedRequestPayload;String credentialScope = date + "/" + service + "/" + "tc3_request";String hashedCanonicalRequest = sha256Hex(canonicalRequest);String stringToSign = algorithm + "\\n" + timestamp + "\\n" + credentialScope + "\\n" + hashedCanonicalRequest;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();String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;try {URL url = new URL("https://" + host);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("POST");connection.setRequestProperty("Authorization", authorization);connection.setRequestProperty("Content-Type", CT_JSON);connection.setRequestProperty("Host", host);connection.setRequestProperty("X-TC-Action", action);connection.setRequestProperty("X-TC-Timestamp", timestamp);connection.setRequestProperty("X-TC-Version", version);connection.setRequestProperty("X-TC-Region", region);// Enable input/output streams and write the payloadconnection.setDoOutput(true);OutputStream os = connection.getOutputStream();os.write(payload.getBytes(UTF8));os.flush();os.close();// Get the responseint responseCode = connection.getResponseCode();if (responseCode == 200) {BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String inputLine;StringBuilder response = new StringBuilder();while ((inputLine = in.readLine()) != null) {response.append(inputLine);}in.close();// Process the response as neededSystem.out.println("Response: " + response.toString());} else {// Handle the error responseSystem.out.println("Error Response Code: " + responseCode);}connection.disconnect();} catch (Exception e) {e.printStackTrace();}}}
package tmsimport ("crypto/hmac""crypto/sha256""encoding/base64""encoding/hex""encoding/json""fmt""io/ioutil""net/http""strconv""strings""time")type textmods struct {Content string}func sha256hexs(s string) string {b := sha256.Sum256([]byte(s))return hex.EncodeToString(b[:])}func hmacsha256s(s, key string) string {hashed := hmac.New(sha256.New, []byte(key))hashed.Write([]byte(s))return string(hashed.Sum(nil))}func DetectTextSingles() {secretId := "" // 密钥IDsecretKey := "" // 密钥Keyhost := "tms.tencentcloudapi.com" // 接口域名algorithm := "TC3-HMAC-SHA256"service := "tms"version := "2020-12-29" // 版本为固定值action := "TextModeration"region := "ap-guangzhou" // 地域var timestamp int64 = time.Now().Unix()// step 1: build canonical request stringhttpRequestMethod := "POST"canonicalURI := "/"canonicalQueryString := ""canonicalHeaders := "content-type:application/json; charset=utf-8\\n" + "host:" + host + "\\n"signedHeaders := "content-type;host"var a = textmods{Content: base64.StdEncoding.EncodeToString([]byte("测试文本内容")), // 接口入参}b, err := json.Marshal(a)if err != nil {fmt.Print(err.Error())return}payload := string(b)hashedRequestPayload := sha256hexs(payload)canonicalRequest := fmt.Sprintf("%s\\n%s\\n%s\\n%s\\n%s\\n%s",httpRequestMethod,canonicalURI,canonicalQueryString,canonicalHeaders,signedHeaders,hashedRequestPayload)// fmt.Println(canonicalRequest)// step 2: build string to signdate := time.Unix(timestamp, 0).UTC().Format("2006-01-02")credentialScope := fmt.Sprintf("%s/%s/tc3_request", date, service)hashedCanonicalRequest := sha256hexs(canonicalRequest)string2sign := fmt.Sprintf("%s\\n%d\\n%s\\n%s",algorithm,timestamp,credentialScope,hashedCanonicalRequest)// fmt.Println(string2sign)// step 3: sign stringsecretDate := hmacsha256s(date, "TC3"+secretKey)secretService := hmacsha256s(service, secretDate)secretSigning := hmacsha256s("tc3_request", secretService)signature := hex.EncodeToString([]byte(hmacsha256s(string2sign, secretSigning)))// fmt.Println(signature)// step 4: build authorizationauthorization := fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",algorithm,secretId,credentialScope,signedHeaders,signature)req, _ := http.NewRequest("POST", "https://"+host, strings.NewReader(payload))req.Header.Set("Authorization", authorization)req.Header.Set("Content-Type", "application/json; charset=utf-8")req.Header.Set("Host", host)req.Header.Set("X-TC-Action", action)req.Header.Set("X-TC-Timestamp", strconv.FormatInt(timestamp, 10))req.Header.Set("X-TC-Version", version)req.Header.Set("X-TC-Region", region)resp, err := (&http.Client{}).Do(req)if err != nil {fmt.Print(err.Error())return}defer resp.Body.Close()respByte, _ := ioutil.ReadAll(resp.Body)fmt.Println(string(respByte))}
#!/usr/bin/env python3# -*- coding:utf-8 -*-import hashlibimport hmacimport jsonimport base64import timefrom datetime import datetimeimport requestsfrom concurrent.futures import ThreadPoolExecutorsecret_id = "" # 密钥IDsecret_key = "" # 密钥Keyservice = "tms"host = "tms.tencentcloudapi.com" # 接口域名endpoint = "https://" + hostregion = 'ap-guangzhou' # 地域version = "2020-12-29" # 版本为固定值algorithm = "TC3-HMAC-SHA256"def do_action(action, params):timestamp = int(time.time())day = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d")# ************* 步骤 1:拼接规范请求串 *************http_request_method = "POST"canonical_url = "/"canonical_querystring = ""ct = "application/json; charset=utf-8"payload = json.dumps(params)canonical_headers = "content-type:%s\\nhost:%s\\n" % (ct, host)signed_headers = "content-type;host"hashed_request_payload = hashlib.sha256(payload.encode("utf-8")).hexdigest()canonical_request = (http_request_method + "\\n" +canonical_url + "\\n" +canonical_querystring + "\\n" +canonical_headers + "\\n" +signed_headers + "\\n" +hashed_request_payload)# print(canonical_request)# ************* 步骤 2:拼接待签名字符串 *************credential_scope = day + "/" + service + "/" + "tc3_request"hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()string_to_sign = (algorithm + "\\n" +str(timestamp) + "\\n" +credential_scope + "\\n" +hashed_canonical_request)# print(string_to_sign)secret_date = sign(("TC3" + secret_key).encode("utf-8"), day)secret_service = sign(secret_date, service)secret_signing = sign(secret_service, "tc3_request")signature = hmac.new(secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()# print(signature)# ************* 步骤 4:拼接 Authorization *************authorization = (algorithm + " " +"Credential=" + secret_id + "/" + credential_scope + ", " +"SignedHeaders=" + signed_headers + ", " +"Signature=" + signature)# print(authorization)headers = {"Authorization": authorization,"Content-Type": "application/json; charset=utf-8","Host": host,"X-TC-Action": action,"X-TC-Timestamp": str(timestamp),"X-TC-Version": version,"X-TC-Region": region}# 发送请求resp = requests.post(url=endpoint, data=payload, headers=headers)return resp# 计算签名摘要函数def sign(key, msg):return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()def image_detect(params):action = "TextModeration"resp = do_action(action, params)return resp.textif __name__ == "__main__":params = []content = "" # 接口参数b4content = base64.b64encode(content.encode()).decode()p = {'BizType': 'default','Content': b4content}params.append(p)executor = ThreadPoolExecutor(max_workers=1)resps = executor.map(image_detect, params)for resp in resps:print(resp)
<?php//简单的后端demo// 接口入参$Content='';$BizType='';$time=time();$Nonce=rand();$Action='TextModeration'; // 接口名称$Version='2020-12-29';$Region='ap-guangzhou';//根据实际需求填写 SecretId 和 secretKey$SecretId='';$secretKey='';//验签过程$param["Nonce"] = $Nonce;$param["Timestamp"] = $time;$param["Region"] = $Region;$param["SecretId"] = $SecretId;$param["Action"] = $Action;$param["Version"] = $Version;$param["Content"] = $Content;$param["BizType"] = $BizType;ksort($param);$signStr = "POSTtms.tencentcloudapi.com/?";foreach ( $param as $key => $value ) {$signStr = $signStr . $key . "=" . $value . "&";}$signStr = substr($signStr, 0, -1);$signature = base64_encode(hash_hmac("sha1", $signStr,$secretKey, true));//$signature=urlencode($signature);//文档要求必须先urlencode//POST数据$post_data = array('Action' => $Action,'Nonce' =>$Nonce,'SecretId'=>$SecretId,'Signature'=>$signature,//签名'Content' =>$Content,'BizType' =>$BizType,'Region' =>$Region,'Timestamp' =>$time,'Version' =>$Version,);//POST请求$url='https://tms.tencentcloudapi.com/';$query = http_build_query($post_data);$options = array('http' => array('method' => 'POST','header' => 'Content-type:application/x-www-form-urlencoded','content' => $query,'timeout' => 15 * 60 // 超时时间(单位:s)));$context = stream_context_create($options);$result = file_get_contents($url,false,$context);$data_arr['code']=1;$data_arr['result']=$result;$data_arr['signature']=$signature;header('content-type:application/json');echo json_encode($data_arr);exit();
签名失败
存在以下签名失败的错误码,请根据实际情况处理。
错误码 | 错误描述 |
AuthFailure.SignatureExpire | 签名过期。Timestamp 与服务器接收到请求的时间相差不得超过五分钟。 |
AuthFailure.SecretIdNotFound | |
AuthFailure.SignatureFailure | 签名错误。可能是签名计算错误,或者签名与实际发送的内容不相符合,也有可能是密钥 SecretKey 错误导致的。 |
AuthFailure.TokenFailure | 临时证书 Token 错误。 |
AuthFailure.InvalidSecretId | 密钥非法(不是云 API 密钥类型)。 |