wechat_params.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package gopay
  2. import (
  3. "crypto/hmac"
  4. "crypto/md5"
  5. "crypto/sha256"
  6. "crypto/tls"
  7. "crypto/x509"
  8. "encoding/hex"
  9. "encoding/xml"
  10. "errors"
  11. "fmt"
  12. "hash"
  13. "io/ioutil"
  14. "strings"
  15. )
  16. type Country int
  17. // 设置支付国家(默认:中国国内)
  18. // 根据支付地区情况设置国家
  19. // country:<China:中国国内,China2:中国国内(冗灾方案),SoutheastAsia:东南亚,Other:其他国家>
  20. func (w *WeChatClient) SetCountry(country Country) (client *WeChatClient) {
  21. w.mu.Lock()
  22. switch country {
  23. case China:
  24. w.BaseURL = wxBaseUrlCh
  25. case China2:
  26. w.BaseURL = wxBaseUrlCh2
  27. case SoutheastAsia:
  28. w.BaseURL = wxBaseUrlHk
  29. case Other:
  30. w.BaseURL = wxBaseUrlUs
  31. default:
  32. w.BaseURL = wxBaseUrlCh
  33. }
  34. w.mu.Unlock()
  35. return w
  36. }
  37. // 添加微信证书 Byte 数组
  38. // certFile:apiclient_cert.pem byte数组
  39. // keyFile:apiclient_key.pem byte数组
  40. // pkcs12File:apiclient_cert.p12 byte数组
  41. func (w *WeChatClient) AddCertFileByte(certFile, keyFile, pkcs12File []byte) {
  42. w.mu.Lock()
  43. w.CertFile = certFile
  44. w.KeyFile = keyFile
  45. w.Pkcs12File = pkcs12File
  46. w.mu.Unlock()
  47. }
  48. // 添加微信证书 Path 路径
  49. // certFilePath:apiclient_cert.pem 路径
  50. // keyFilePath:apiclient_key.pem 路径
  51. // pkcs12FilePath:apiclient_cert.p12 路径
  52. // 返回err
  53. func (w *WeChatClient) AddCertFilePath(certFilePath, keyFilePath, pkcs12FilePath string) (err error) {
  54. w.mu.Lock()
  55. defer w.mu.Unlock()
  56. var (
  57. cert, key, pkcs []byte
  58. )
  59. if cert, err = ioutil.ReadFile(certFilePath); err != nil {
  60. return
  61. }
  62. if key, err = ioutil.ReadFile(keyFilePath); err != nil {
  63. return
  64. }
  65. if pkcs, err = ioutil.ReadFile(pkcs12FilePath); err != nil {
  66. return
  67. }
  68. w.CertFile = cert
  69. w.KeyFile = key
  70. w.Pkcs12File = pkcs
  71. return
  72. }
  73. func (w *WeChatClient) addCertConfig(certFilePath, keyFilePath, pkcs12FilePath string) (tlsConfig *tls.Config, err error) {
  74. var (
  75. pkcs []byte
  76. certificate tls.Certificate
  77. pkcsPool = x509.NewCertPool()
  78. )
  79. if certFilePath != null && keyFilePath != null && pkcs12FilePath != null {
  80. if pkcs, err = ioutil.ReadFile(pkcs12FilePath); err != nil {
  81. return nil, fmt.Errorf("ioutil.ReadFile:%s", err.Error())
  82. }
  83. pkcsPool.AppendCertsFromPEM(pkcs)
  84. if certificate, err = tls.LoadX509KeyPair(certFilePath, keyFilePath); err != nil {
  85. return nil, fmt.Errorf("tls.LoadX509KeyPair:%s", err.Error())
  86. }
  87. tlsConfig = &tls.Config{
  88. Certificates: []tls.Certificate{certificate},
  89. RootCAs: pkcsPool,
  90. InsecureSkipVerify: true}
  91. return
  92. }
  93. pkcsPool.AppendCertsFromPEM(w.Pkcs12File)
  94. if certificate, err = tls.X509KeyPair(w.CertFile, w.KeyFile); err != nil {
  95. return nil, fmt.Errorf("tls.X509KeyPair:%s", err.Error())
  96. }
  97. tlsConfig = &tls.Config{
  98. Certificates: []tls.Certificate{certificate},
  99. RootCAs: pkcsPool,
  100. InsecureSkipVerify: true}
  101. return
  102. }
  103. // 获取微信支付正式环境Sign值
  104. func getWeChatReleaseSign(apiKey string, signType string, bm BodyMap) (sign string) {
  105. var h hash.Hash
  106. if signType == SignType_HMAC_SHA256 {
  107. h = hmac.New(sha256.New, []byte(apiKey))
  108. } else {
  109. h = md5.New()
  110. }
  111. h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
  112. sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  113. return
  114. }
  115. // 获取微信支付沙箱环境Sign值
  116. func getWeChatSignBoxSign(mchId, apiKey string, bm BodyMap) (sign string, err error) {
  117. var (
  118. sandBoxApiKey string
  119. h hash.Hash
  120. )
  121. if sandBoxApiKey, err = getSanBoxKey(mchId, GetRandomString(32), apiKey, SignType_MD5); err != nil {
  122. return
  123. }
  124. h = md5.New()
  125. h.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
  126. sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  127. return
  128. }
  129. // 从微信提供的接口获取:SandboxSignKey
  130. func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
  131. bm := make(BodyMap)
  132. bm.Set("mch_id", mchId)
  133. bm.Set("nonce_str", nonceStr)
  134. //沙箱环境:获取沙箱环境ApiKey
  135. if key, err = getSanBoxSignKey(mchId, nonceStr, getWeChatReleaseSign(apiKey, signType, bm)); err != nil {
  136. return
  137. }
  138. return
  139. }
  140. // 从微信提供的接口获取:SandboxSignkey
  141. func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
  142. reqs := make(BodyMap)
  143. reqs.Set("mch_id", mchId)
  144. reqs.Set("nonce_str", nonceStr)
  145. reqs.Set("sign", sign)
  146. var (
  147. byteList []byte
  148. errorList []error
  149. keyResponse *getSignKeyResponse
  150. )
  151. if _, byteList, errorList = HttpAgent().Post(wxSandboxGetsignkey).Type("xml").SendString(generateXml(reqs)).EndBytes(); len(errorList) > 0 {
  152. return null, errorList[0]
  153. }
  154. keyResponse = new(getSignKeyResponse)
  155. if err = xml.Unmarshal(byteList, keyResponse); err != nil {
  156. return
  157. }
  158. if keyResponse.ReturnCode == "FAIL" {
  159. return null, errors.New(keyResponse.ReturnMsg)
  160. }
  161. return keyResponse.SandboxSignkey, nil
  162. }
  163. // 生成请求XML的Body体
  164. func generateXml(bm BodyMap) (reqXml string) {
  165. var buffer strings.Builder
  166. buffer.WriteString("<xml>")
  167. for key := range bm {
  168. buffer.WriteByte('<')
  169. buffer.WriteString(key)
  170. buffer.WriteString("><![CDATA[")
  171. buffer.WriteString(bm.Get(key))
  172. buffer.WriteString("]]></")
  173. buffer.WriteString(key)
  174. buffer.WriteByte('>')
  175. }
  176. buffer.WriteString("</xml>")
  177. reqXml = buffer.String()
  178. return
  179. }