166 lines
3.8 KiB
Go
166 lines
3.8 KiB
Go
package qcloud
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
func RequestApi(conf TencentApiRequestConf) ([]byte, error) {
|
|
if conf.Region == "" {
|
|
conf.Region = "ap-guangzhou"
|
|
}
|
|
|
|
var (
|
|
host = fmt.Sprintf("%s.tencentcloudapi.com", conf.Product)
|
|
endpoint = fmt.Sprintf("https://%s", host)
|
|
algorithm = "TC3-HMAC-SHA256"
|
|
timestamp = time.Now().Unix()
|
|
date = time.Unix(timestamp, 0).UTC().Format("2006-01-02")
|
|
)
|
|
|
|
// ************* 步骤 1:拼接规范请求串 *************
|
|
var (
|
|
httpReqMethod = conf.Method
|
|
canonicalURI = "/"
|
|
payload string
|
|
canonicalQuery string
|
|
contentType string
|
|
)
|
|
|
|
switch conf.Method {
|
|
case "GET":
|
|
payload = ""
|
|
canonicalQuery = join(conf.Data)
|
|
contentType = "application/x-www-form-urlencoded; charset=utf-8"
|
|
case "POST":
|
|
payloadBytes, _ := json.Marshal(conf.Data)
|
|
payload = string(payloadBytes)
|
|
canonicalQuery = ""
|
|
contentType = "application/json; charset=utf-8"
|
|
}
|
|
|
|
// fmt.Println(canonicalQuery)
|
|
var (
|
|
canonicalHeaders = fmt.Sprintf("content-type:%s\nhost:%s\n", contentType, host)
|
|
signedHeaders = "content-type;host"
|
|
hashedReqPayload = fmt.Sprintf("%x", sha256.Sum256([]byte(payload)))
|
|
)
|
|
canonicalReq := fmt.Sprintf(
|
|
"%s\n%s\n%s\n%s\n%s\n%s",
|
|
httpReqMethod, canonicalURI, canonicalQuery,
|
|
canonicalHeaders, signedHeaders, hashedReqPayload,
|
|
)
|
|
|
|
// ************* 步骤 2:拼接待签名字符串 *************
|
|
var (
|
|
credentialScope = fmt.Sprintf("%s/%s/tc3_request", date, conf.Product)
|
|
hashedCanonicalReq = fmt.Sprintf("%x", sha256.Sum256([]byte(canonicalReq)))
|
|
)
|
|
stringToSign := fmt.Sprintf(
|
|
"%s\n%d\n%s\n%s",
|
|
algorithm, timestamp, credentialScope, hashedCanonicalReq,
|
|
)
|
|
|
|
// ************* 步骤 3:计算签名 *************
|
|
var (
|
|
secretDate = sign([]byte(fmt.Sprintf("TC3%s", conf.SecretKey)), date)
|
|
secretService = sign(secretDate, conf.Product)
|
|
secretSigning = sign(secretService, "tc3_request")
|
|
signature = hex.EncodeToString(sign(secretSigning, stringToSign))
|
|
)
|
|
|
|
// ************* 步骤 4:拼接 Authorization *************
|
|
authorization := fmt.Sprintf(
|
|
"%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
|
|
algorithm, conf.SecretID, credentialScope, signedHeaders, signature,
|
|
)
|
|
headers := map[string]string{
|
|
"Authorization": authorization,
|
|
"Content-Type": contentType,
|
|
"Host": host,
|
|
"X-TC-Action": conf.Action,
|
|
"X-TC-Timestamp": fmt.Sprintf("%d", timestamp),
|
|
"X-TC-Version": conf.Version,
|
|
"X-TC-Region": conf.Region,
|
|
}
|
|
|
|
// 发送 Http 请求
|
|
var (
|
|
client = &http.Client{}
|
|
reqUrl string
|
|
reqBody *bytes.Buffer
|
|
)
|
|
switch httpReqMethod {
|
|
case "GET":
|
|
reqUrl = endpoint + "?" + join(conf.Data)
|
|
reqBody = bytes.NewBuffer([]byte(""))
|
|
case "POST":
|
|
reqUrl = endpoint
|
|
jsonData, _ := json.Marshal(conf.Data)
|
|
reqBody = bytes.NewBuffer(jsonData)
|
|
}
|
|
|
|
req, _ := http.NewRequest(httpReqMethod, reqUrl, reqBody)
|
|
for key, value := range headers {
|
|
req.Header.Set(key, value)
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// fmt.Println(req.Header)
|
|
// fmt.Println(resp.Status)
|
|
|
|
defer resp.Body.Close()
|
|
|
|
// 读取响应数据
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return body, nil
|
|
}
|
|
|
|
type TencentApiRequestConf struct {
|
|
SecretID string
|
|
SecretKey string
|
|
Region string
|
|
|
|
Product string
|
|
Action string
|
|
Version string
|
|
Method string
|
|
|
|
Data map[string]string
|
|
}
|
|
|
|
func join(params map[string]string) string {
|
|
values := url.Values{}
|
|
for key, value := range params {
|
|
values.Add(key, value)
|
|
}
|
|
return values.Encode()
|
|
}
|
|
|
|
func sign(key []byte, msg string) []byte {
|
|
h := hmac.New(sha256.New, key)
|
|
h.Write([]byte(msg))
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
func base64EncodeStr(str string) string {
|
|
return base64.StdEncoding.EncodeToString([]byte(str))
|
|
}
|