package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"time"
"github.com/forgoer/openssl"
)
const (
SignatureMessageFormat = "%s\n%d\n%s\n%s" // 数字签名原文格式
HeaderAuthorizationFormat = "%s app_id=%s,mch_id=%s,nonce_str=%s,timestamp=%d,signature=%s"
)
type QueryReq struct {
AppID string `json:"app_id"`
MchID string `json:"mch_id"`
TransactionID string `json:"transaction_id,omitempty"`
OutTradeNo string `json:"out_trade_no,omitempty"`
}
func main() {
appSecret := "**********" // 应用密钥
reqPath := "/v1/transaction/query" // 请求接口路径
queryReq := QueryReq{
AppID: "**********", // 应用ID
MchID: "**********", // 商户ID
TransactionID: "**********", // 平台订单号
OutTradeNo: "**********", // 商户订单号
}
b, _ := json.Marshal(queryReq)
// 签名
authorization, err := GenerateAuthorizationHeader(queryReq.AppID, queryReq.MchID, reqPath, string(b), appSecret)
if err != nil {
panic(err)
}
// 请求接口
url := "" + reqPath
payload := bytes.NewBuffer(b)
req, _ := http.NewRequest("POST", url, payload)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", authorization)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
// 签名
func GenerateAuthorizationHeader(appID, mchID, reqURL, signBody, appSecret string) (string, error) {
nonceStr := RandomString(32)
timestamp := time.Now().Unix()
message := fmt.Sprintf(SignatureMessageFormat, reqURL, timestamp, nonceStr, signBody)
signatureResult, err := AesECBEncrypt(message, appSecret)
if err != nil {
return "", err
}
authorization := fmt.Sprintf(
HeaderAuthorizationFormat, getAuthorizationType(), appID,
mchID, nonceStr, timestamp, signatureResult,
)
return authorization, nil
}
// AES加密
func AesECBEncrypt(orig, key string) (string, error) {
dst, _ := openssl.AesECBEncrypt([]byte(orig), []byte(key), openssl.PKCS7_PADDING)
return base64.StdEncoding.EncodeToString(dst), nil
}
// AES解密
func AesECBDecrypt(crypted, key string) (string, error) {
x := len(crypted) * 3 % 4
switch {
case x == 2:
crypted += "=="
case x == 1:
crypted += "="
}
crytedByte, err := base64.StdEncoding.DecodeString(crypted)
if err != nil {
return "", err
}
origData, err := openssl.AesECBDecrypt(crytedByte, []byte(key), openssl.PKCS7_PADDING)
if err != nil {
return "", err
}
return string(origData), err
}
// 生成随机字符
func RandomString(length int) string {
str := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
var result []byte
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < length; i++ {
result = append(result, str[rnd.Intn(len(str))])
}
return string(result)
}
func getAuthorizationType() string {
return "TTPAY-AES-256-ECB"
}