| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package asign
- import (
- "bytes"
- "crypto"
- "crypto/md5"
- "crypto/rand"
- "crypto/rsa"
- "crypto/sha1"
- "crypto/x509"
- "encoding/base64"
- "encoding/hex"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "mime/multipart"
- "mtp2_if/config"
- "mtp2_if/logger"
- "net/http"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
- "github.com/bytedance/sonic"
- "github.com/bytedance/sonic/encoder"
- )
- func APIPost[T1 APIReqData, T2 APIRspData](req APIReq[T1], apiPort APIURL) (rsp *APIRsp[T2], err error) {
- apiUrl := config.SerCfg.AsignCfg.Url + string(apiPort)
- var rspBody []byte
- rspBody, err = httpPost(apiUrl, req.Data)
- if err != nil {
- return
- }
- rspStr := string(rspBody)
- if len(rspStr) == 0 {
- logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
- err = errors.New("调用接口返回内容为空")
- return
- }
- rsp = new(APIRsp[T2])
- err = sonic.Unmarshal(rspBody, rsp)
- return
- }
- func httpPost(apiUrl string, bizData ...interface{}) (rspBody []byte, err error) {
- appId := config.SerCfg.AsignCfg.AppId
- privateKey := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", config.SerCfg.AsignCfg.PrivateKey)
- // fuck asign dev.
- timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 10000*60))
- // 排序key
- var b []byte
- if len(bizData) == 1 {
- b, err = encoder.Encode(bizData[0], encoder.SortMapKeys)
- } else {
- b, err = encoder.Encode(bizData, encoder.SortMapKeys)
- }
- if err != nil {
- logger.GetLogger().Errorf("处理入参排序失败:" + err.Error())
- return
- }
- sortedData := string(b)
- // 签名
- signature, err := getSignature(sortedData, appId, timestamp, privateKey)
- if err != nil {
- logger.GetLogger().Errorf("签名失败:" + err.Error())
- return
- }
- // 构建form-data请求参数
- var requestBody bytes.Buffer
- multipartWriter := multipart.NewWriter(&requestBody)
- multipartWriter.WriteField("appId", appId)
- multipartWriter.WriteField("timestamp", timestamp)
- multipartWriter.WriteField("bizData", sortedData)
- multipartWriter.Close()
- // 构建请求
- req, err := http.NewRequest("POST", apiUrl, &requestBody)
- // 设置请求头
- req.Header.Set("sign", signature)
- req.Header.Set("timestamp", timestamp)
- req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
- // 调用接口
- logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", sortedData)
- client := &http.Client{}
- rsp, err := client.Do(req)
- if err != nil {
- logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
- return
- }
- defer rsp.Body.Close()
- rspBody, err = io.ReadAll(rsp.Body)
- logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", string(rspBody))
- return
- }
- // 签名规范:
- // 1、表单提交方式:form-data
- // 示例:1B2M2Y8AsgTpgAmY7PhCfg==
- // 2、请求头部参数
- // 参数1:sign(签名值,具体算法参考一下的前面算法)
- // 参数2:timestamp(时间戳,13位)
- // 3、请求体参数:
- // 参数1:appId(appId值,每个接入者唯一一个)
- // 参数2:timestamp(时间戳,13位,与上述一致)
- // 参数3:bizData(json字符串,举个例子,比方说要传合同编号如:{"contractNo":"0001"})
- // 4、签名算法:
- // 4.1、将上述3所属的bizData(json字符串),按照阿拉伯字母排序(如:{"ba":1,"ac":2}--->{"ac":2,"ba":1}),
- // 4.2、将4.1排序后的字符串,将【bizData+md5(bizData)+ appId + timestatmp】拼接后利用RSA非对称加密算法(SHA1withRSA),计算出最后的签名sign,对其base64编码,放入head的key(sign)中。
- //
- // String sign ;
- // String rsaSuffix = jsonStr + DigestUtils.md5Hex ( jsonStr ) + appId + timestatmp ;
- // byte [] bytes = RSAUtils.generateSHA1withRSASignature ( rsaSuffix, privateKey ) ;
- // try {
- // sign = Base64Utils.encode ( bytes ) ;
- // sign = sign.replaceAll ( " \r\n" , "" ) ;
- // } catch ( Exception e ) {
- // log.error( "sdk异常", e ) ;
- // return ApiRespBody.create ( ApiResponseInfo. _ERROR ) ;
- // }
- func getSignature(sortedData string, appId, timestamp, privateKey string) (signature string, err error) {
- pem10, _ := pem.Decode([]byte(privateKey))
- privateKey10I, _ := x509.ParsePKCS8PrivateKey(pem10.Bytes)
- privateKey10 := privateKey10I.(*rsa.PrivateKey)
- // md5(bizData)
- m := md5.New()
- m.Write([]byte(sortedData))
- bdMd5Hx := hex.EncodeToString(m.Sum(nil))
- // 待签内容
- message := sortedData + bdMd5Hx + appId + timestamp
- h := sha1.New()
- h.Write([]byte(message))
- sum := h.Sum(nil)
- // 使用私钥进行签名
- sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey10, crypto.SHA1, sum)
- if err != nil {
- return
- }
- // fmt.Println(signature)
- signature = base64.StdEncoding.EncodeToString(sign)
- signature = strings.ReplaceAll(signature, "\r\n", "")
- return
- }
- // SortMapByKey 按key排序map返回string -- 已经不使用的方法
- func SortMapByKey(data map[string]interface{}) (sortedData string) {
- keys := make([]string, 0, len(data))
- for k := range data {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- for i, k := range keys {
- if i > 0 {
- sortedData += ","
- }
- // 判断是否指针
- v := reflect.ValueOf(data[k])
- if v.Kind() == reflect.Ptr {
- switch data[k].(type) {
- case *string:
- sortedData += fmt.Sprintf(`"%s":"%s"`, k, *(data[k].(*string)))
- case *map[string]interface{}:
- sortedData += fmt.Sprintf(`"%s":%s`, k, SortMapByKey(*(data[k].(*map[string]interface{}))))
- case *[]interface{}:
- list := data[k].([]interface{})
- sortedData += fmt.Sprintf(`"%s":[`, k)
- for j, item := range list {
- if j > 0 {
- sortedData += ","
- }
- sortedData += SortMapByKey(item.(map[string]interface{}))
- }
- sortedData += "]"
- default:
- sortedData += fmt.Sprintf(`"%s":%v`, k, reflect.ValueOf(data[k]).Elem())
- }
- } else {
- switch data[k].(type) {
- case string:
- sortedData += fmt.Sprintf(`"%s":"%s"`, k, data[k].(string))
- case map[string]interface{}:
- sortedData += fmt.Sprintf(`"%s":%s`, k, SortMapByKey(data[k].(map[string]interface{})))
- case []interface{}:
- list := data[k].([]interface{})
- sortedData += fmt.Sprintf(`"%s":[`, k)
- for j, item := range list {
- if j > 0 {
- sortedData += ","
- }
- sortedData += SortMapByKey(item.(map[string]interface{}))
- }
- sortedData += "]"
- default:
- sortedData += fmt.Sprintf(`"%s":%v`, k, data[k])
- }
- }
- }
- return fmt.Sprintf("{%s}", sortedData)
- }
|