api.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package asign
  2. import (
  3. "bytes"
  4. "crypto"
  5. "crypto/md5"
  6. "crypto/rand"
  7. "crypto/rsa"
  8. "crypto/sha1"
  9. "crypto/x509"
  10. "encoding/base64"
  11. "encoding/hex"
  12. "encoding/json"
  13. "encoding/pem"
  14. "fmt"
  15. "io"
  16. "mime/multipart"
  17. "mtp2_if/config"
  18. "mtp2_if/logger"
  19. "net/http"
  20. "reflect"
  21. "sort"
  22. "strconv"
  23. "strings"
  24. "time"
  25. "github.com/fatih/structs"
  26. )
  27. func APIPost[T1 APIReqData, T2 APIRspData](req APIReq[T1], apiPort APIURL) (rsp *APIRsp[T2], err error) {
  28. apiUrl := config.SerCfg.AsignCfg.Url + string(apiPort)
  29. var rspBody []byte
  30. if len(req.Datas) > 0 {
  31. // 数组入参
  32. reqArray := make([]map[string]interface{}, 0)
  33. for _, item := range req.Datas {
  34. reqArray = append(reqArray, structs.Map(item))
  35. }
  36. logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqArray)
  37. rspBody, err = httpPost_Array(apiUrl, reqArray)
  38. } else {
  39. // 对象入参
  40. reqMap := structs.Map(req.Data)
  41. logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
  42. rspBody, err = httpPost(apiUrl, reqMap)
  43. }
  44. if err != nil {
  45. logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
  46. return
  47. }
  48. rspStr := string(rspBody)
  49. if len(rspStr) == 0 {
  50. logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
  51. return
  52. }
  53. logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
  54. rsp = new(APIRsp[T2])
  55. err = json.Unmarshal(rspBody, rsp)
  56. return
  57. }
  58. func httpPost(apiUrl string, bizData map[string]interface{}) (rspBody []byte, err error) {
  59. appId := config.SerCfg.AsignCfg.AppId
  60. privateKey := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", config.SerCfg.AsignCfg.PrivateKey)
  61. // fuck asign dev.
  62. timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 10000*60))
  63. // 签名
  64. sortedData := sortMapByKey(bizData)
  65. signature, err := getSignature(sortedData, appId, timestamp, privateKey)
  66. if err != nil {
  67. logger.GetLogger().Errorf("签名失败:" + err.Error())
  68. return
  69. }
  70. // 构建form-data请求参数
  71. var requestBody bytes.Buffer
  72. multipartWriter := multipart.NewWriter(&requestBody)
  73. multipartWriter.WriteField("appId", appId)
  74. multipartWriter.WriteField("timestamp", timestamp)
  75. multipartWriter.WriteField("bizData", sortedData)
  76. multipartWriter.Close()
  77. // 构建请求
  78. req, err := http.NewRequest("POST", apiUrl, &requestBody)
  79. // 设置请求头
  80. req.Header.Set("sign", signature)
  81. req.Header.Set("timestamp", timestamp)
  82. req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
  83. // 调用接口
  84. client := &http.Client{}
  85. rsp, err := client.Do(req)
  86. if err != nil {
  87. logger.GetLogger().Errorf("调用接口失败:" + err.Error())
  88. return
  89. }
  90. defer rsp.Body.Close()
  91. rspBody, err = io.ReadAll(rsp.Body)
  92. return
  93. }
  94. // bizData入参为数组
  95. func httpPost_Array(apiUrl string, bizData []map[string]interface{}) (rspBody []byte, err error) {
  96. appId := config.SerCfg.AsignCfg.AppId
  97. privateKey := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", config.SerCfg.AsignCfg.PrivateKey)
  98. // fuck asign dev.
  99. timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 10000*60))
  100. // 签名
  101. sortedData := "["
  102. for i, item := range bizData {
  103. if i > 0 {
  104. sortedData += ","
  105. }
  106. sortedData += sortMapByKey(item)
  107. }
  108. sortedData += "]"
  109. signature, err := getSignature(sortedData, appId, timestamp, privateKey)
  110. if err != nil {
  111. logger.GetLogger().Errorf("签名失败:" + err.Error())
  112. return
  113. }
  114. // 构建form-data请求参数
  115. var requestBody bytes.Buffer
  116. multipartWriter := multipart.NewWriter(&requestBody)
  117. multipartWriter.WriteField("appId", appId)
  118. multipartWriter.WriteField("timestamp", timestamp)
  119. multipartWriter.WriteField("bizData", sortedData)
  120. multipartWriter.Close()
  121. // 构建请求
  122. req, err := http.NewRequest("POST", apiUrl, &requestBody)
  123. // 设置请求头
  124. req.Header.Set("sign", signature)
  125. req.Header.Set("timestamp", timestamp)
  126. req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
  127. // 调用接口
  128. client := &http.Client{}
  129. rsp, err := client.Do(req)
  130. if err != nil {
  131. logger.GetLogger().Errorf("调用接口失败:" + err.Error())
  132. return
  133. }
  134. defer rsp.Body.Close()
  135. rspBody, err = io.ReadAll(rsp.Body)
  136. return
  137. }
  138. // 签名规范:
  139. // 1、表单提交方式:form-data
  140. // 示例:1B2M2Y8AsgTpgAmY7PhCfg==
  141. // 2、请求头部参数
  142. // 参数1:sign(签名值,具体算法参考一下的前面算法)
  143. // 参数2:timestamp(时间戳,13位)
  144. // 3、请求体参数:
  145. // 参数1:appId(appId值,每个接入者唯一一个)
  146. // 参数2:timestamp(时间戳,13位,与上述一致)
  147. // 参数3:bizData(json字符串,举个例子,比方说要传合同编号如:{"contractNo":"0001"})
  148. // 4、签名算法:
  149. // 4.1、将上述3所属的bizData(json字符串),按照阿拉伯字母排序(如:{"ba":1,"ac":2}--->{"ac":2,"ba":1}),
  150. // 4.2、将4.1排序后的字符串,将【bizData+md5(bizData)+ appId + timestatmp】拼接后利用RSA非对称加密算法(SHA1withRSA),计算出最后的签名sign,对其base64编码,放入head的key(sign)中。
  151. //
  152. // String sign ;
  153. // String rsaSuffix = jsonStr + DigestUtils.md5Hex ( jsonStr ) + appId + timestatmp ;
  154. // byte [] bytes = RSAUtils.generateSHA1withRSASignature ( rsaSuffix, privateKey ) ;
  155. // try {
  156. // sign = Base64Utils.encode ( bytes ) ;
  157. // sign = sign.replaceAll ( " \r\n" , "" ) ;
  158. // } catch ( Exception e ) {
  159. // log.error( "sdk异常", e ) ;
  160. // return ApiRespBody.create ( ApiResponseInfo. _ERROR ) ;
  161. // }
  162. func getSignature(sortedData string, appId, timestamp, privateKey string) (signature string, err error) {
  163. pem10, _ := pem.Decode([]byte(privateKey))
  164. privateKey10I, _ := x509.ParsePKCS8PrivateKey(pem10.Bytes)
  165. privateKey10 := privateKey10I.(*rsa.PrivateKey)
  166. // md5(bizData)
  167. m := md5.New()
  168. m.Write([]byte(sortedData))
  169. bdMd5Hx := hex.EncodeToString(m.Sum(nil))
  170. // 待签内容
  171. message := sortedData + bdMd5Hx + appId + timestamp
  172. h := sha1.New()
  173. h.Write([]byte(message))
  174. sum := h.Sum(nil)
  175. // 使用私钥进行签名
  176. sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey10, crypto.SHA1, sum)
  177. if err != nil {
  178. fmt.Println("Error signing:", err)
  179. return
  180. }
  181. // fmt.Println(signature)
  182. signature = base64.StdEncoding.EncodeToString(sign)
  183. signature = strings.ReplaceAll(signature, "\r\n", "")
  184. return
  185. }
  186. // sortMapByKey 按key排序map返回string
  187. func sortMapByKey(data map[string]interface{}) (sortedData string) {
  188. keys := make([]string, 0, len(data))
  189. for k := range data {
  190. keys = append(keys, k)
  191. }
  192. sort.Strings(keys)
  193. for i, k := range keys {
  194. if i > 0 {
  195. sortedData += ","
  196. }
  197. // 判断是否指针
  198. v := reflect.ValueOf(data[k])
  199. if v.Kind() == reflect.Ptr {
  200. switch data[k].(type) {
  201. case *string:
  202. sortedData += fmt.Sprintf(`"%s":"%s"`, k, *(data[k].(*string)))
  203. case *map[string]interface{}:
  204. sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(*(data[k].(*map[string]interface{}))))
  205. case *[]interface{}:
  206. list := data[k].([]interface{})
  207. sortedData += fmt.Sprintf(`"%s":[`, k)
  208. for j, item := range list {
  209. if j > 0 {
  210. sortedData += ","
  211. }
  212. sortedData += sortMapByKey(item.(map[string]interface{}))
  213. }
  214. sortedData += "]"
  215. default:
  216. sortedData += fmt.Sprintf(`"%s":%v`, k, reflect.ValueOf(data[k]).Elem())
  217. }
  218. } else {
  219. switch data[k].(type) {
  220. case string:
  221. sortedData += fmt.Sprintf(`"%s":"%s"`, k, data[k].(string))
  222. case map[string]interface{}:
  223. sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(data[k].(map[string]interface{})))
  224. case []interface{}:
  225. list := data[k].([]interface{})
  226. sortedData += fmt.Sprintf(`"%s":[`, k)
  227. for j, item := range list {
  228. if j > 0 {
  229. sortedData += ","
  230. }
  231. sortedData += sortMapByKey(item.(map[string]interface{}))
  232. }
  233. sortedData += "]"
  234. default:
  235. sortedData += fmt.Sprintf(`"%s":%v`, k, data[k])
  236. }
  237. }
  238. }
  239. return fmt.Sprintf("{%s}", sortedData)
  240. }