You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.7 KiB

3 years ago
  1. // @Time : 2020/7/9 11:14
  2. // @Author : 黑白配
  3. // @File : index
  4. // @PackageName:public
  5. // @Description:
  6. package config
  7. import (
  8. "bytes"
  9. "crypto"
  10. "crypto/rand"
  11. "crypto/rsa"
  12. "crypto/sha256"
  13. "crypto/x509"
  14. "encoding/base64"
  15. "encoding/json"
  16. "encoding/pem"
  17. "errors"
  18. "fmt"
  19. "io/ioutil"
  20. "net/http"
  21. "time"
  22. "git.ouxuan.net/3136352472/wxpay/utils"
  23. )
  24. type V3 struct {
  25. MchID string `json:"mchid"` // 商户ID
  26. ClientKeyPath string `json:"clientKeyPath"` // 证书私钥路径
  27. SerialNo string `json:"serialNo"` // 证书编号
  28. }
  29. func (m V3) Request(api string, body interface{}, out interface{}) error {
  30. var request *http.Request
  31. client := http.Client{}
  32. host := "https://api.mch.weixin.qq.com"
  33. if body != nil {
  34. b, _ := json.Marshal(body)
  35. request, _ = http.NewRequest("POST", host+api, bytes.NewReader(b))
  36. } else {
  37. request, _ = http.NewRequest("GET", host+api, nil)
  38. }
  39. sign, err := m.Sign(api, body)
  40. if err != nil {
  41. return err
  42. }
  43. request.Header.Add("Accept", "application/json")
  44. request.Header.Add("Content-Type", "application/json")
  45. request.Header.Add("Authorization", sign)
  46. if resp, err := client.Do(request); err == nil {
  47. defer resp.Body.Close()
  48. b, _ := ioutil.ReadAll(resp.Body)
  49. if len(b) > 0 && out != nil {
  50. return json.Unmarshal(b, out)
  51. } else {
  52. return nil
  53. }
  54. } else {
  55. return err
  56. }
  57. }
  58. // Sign 签名
  59. // @param method string 请求类型
  60. // @param url string 请求地址
  61. // @param body interface 请求数据
  62. func (m V3) Sign(url string, body interface{}) (string, error) {
  63. var data = ""
  64. var method = "GET"
  65. t := time.Now().Unix()
  66. randomStr := utils.RandomStr()
  67. if body != nil {
  68. b, _ := json.Marshal(body)
  69. data = string(b)
  70. method = "POST"
  71. }
  72. str := fmt.Sprintf("%s\n%s\n%d\n%s\n%s\n", method, url, t, randomStr, data)
  73. key, _ := ioutil.ReadFile(m.ClientKeyPath)
  74. sign, err := m.rsaEncrypt([]byte(str), key)
  75. return fmt.Sprintf("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\","+
  76. "signature=\"%s\",timestamp=\"%d\",serial_no=\"%s\"", m.MchID, randomStr, sign, t, m.SerialNo), err
  77. }
  78. // 私钥加密
  79. func (m V3) rsaEncrypt(data, keyBytes []byte) (string, error) {
  80. //解密pem格式的私钥
  81. block, _ := pem.Decode(keyBytes)
  82. if block == nil {
  83. return "", errors.New("public key error")
  84. }
  85. // 解析私钥
  86. pubInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  87. if err != nil {
  88. return "", err
  89. }
  90. // 类型断言
  91. pub := pubInterface.(*rsa.PrivateKey)
  92. //加密
  93. msg := sha256.Sum256(data)
  94. sign, err := rsa.SignPKCS1v15(rand.Reader, pub, crypto.SHA256, msg[:])
  95. if err != nil {
  96. return "", err
  97. }
  98. return base64.StdEncoding.EncodeToString(sign), nil
  99. }
  100. type Result struct {
  101. Code string `json:"code,omitempty"` // 错误代码
  102. Message string `json:"message,omitempty"` // 错误信息
  103. }