weChatServer.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package server
  2. import (
  3. "crypto"
  4. "crypto/rand"
  5. "crypto/rsa"
  6. "crypto/x509"
  7. "encoding/base64"
  8. "encoding/json"
  9. "encoding/pem"
  10. "errors"
  11. "fmt"
  12. "github.com/shopspring/decimal"
  13. "github.com/spf13/viper"
  14. "go_zh/pkg/http"
  15. "go_zh/pkg/utils"
  16. "net/url"
  17. "os"
  18. "sync"
  19. "time"
  20. )
  21. type WeChatServer struct {
  22. MchId string //微信支付商户号
  23. PrivateKey string //微信支付私钥
  24. CertFile string //公钥证书地址
  25. KeyFile string //私钥证书地址
  26. AppId string //公众号id
  27. AppSecret string //公众号密钥
  28. AppletId string //小程序appid
  29. AppletKey string //小程序密钥
  30. CertificateSerialNo string //商户API证书序列号
  31. WechatPayPublicKeyId string //微信支付公钥ID
  32. privateKeyInfo *rsa.PrivateKey
  33. wechatPayPublicKeyInfo *rsa.PublicKey
  34. }
  35. // 小程序登录信息返回结构体
  36. type AppletsOpenData struct {
  37. ErrorMsg string `json:"errmsg"`
  38. ErrorCode int `json:"errcode"`
  39. UnionId string `json:"unionid"`
  40. SessionKey string `json:"session_key"`
  41. Openid string `json:"openid"`
  42. }
  43. var (
  44. weChatServerInstance *WeChatServer
  45. weChatServerOnce sync.Once
  46. )
  47. // GetWeChatServerInstance 获取单例实例
  48. func GetWeChatServerInstance() *WeChatServer {
  49. weChatServerOnce.Do(func() {
  50. weChatServerInstance = &WeChatServer{
  51. MchId: viper.GetString("weChat.mchId"),
  52. PrivateKey: viper.GetString("weChat.privateKey"),
  53. CertFile: viper.GetString("weChat.certFile"),
  54. KeyFile: viper.GetString("weChat.keyFile"),
  55. AppId: viper.GetString("weChat.appId"),
  56. AppSecret: viper.GetString("weChat.appSecret"),
  57. AppletId: viper.GetString("weChat.appletId"),
  58. AppletKey: viper.GetString("weChat.appletKey"),
  59. CertificateSerialNo: viper.GetString("weChat.certificateSerialNo"),
  60. WechatPayPublicKeyId: viper.GetString("weChat.wechatPayPublicKeyId"),
  61. }
  62. privateKey, _ := LoadPrivateKeyWithPath(weChatServerInstance.KeyFile)
  63. weChatServerInstance.privateKeyInfo = privateKey
  64. wechatPayPublicKey, _ := LoadPublicKeyWithPath(weChatServerInstance.CertFile)
  65. weChatServerInstance.wechatPayPublicKeyInfo = wechatPayPublicKey
  66. })
  67. return weChatServerInstance
  68. }
  69. // JsapiPrepayResponse 微信支付jsapi 返回信息结构体
  70. type JsapiPrepayResponse struct {
  71. PrepayId string `json:"prepay_id,omitempty"`
  72. }
  73. // GetAppletsOpenId 微信小程序获取登录openId
  74. func (wx *WeChatServer) GetAppletsOpenId(code string) (AppletsOpenData, error) {
  75. curlUrl := "https://api.weixin.qq.com/sns/jscode2session"
  76. //发起http get请求
  77. var appletsOpenRes AppletsOpenData
  78. requestData := http.RequestData{}
  79. err := requestData.ConstructRequest(curlUrl)
  80. if err != nil {
  81. return appletsOpenRes, err
  82. }
  83. requestData.SetData("grant_type", "authorization_code")
  84. requestData.SetData("appid", wx.AppletId)
  85. requestData.SetData("secret", wx.AppletKey)
  86. requestData.SetData("js_code", code)
  87. ret, err := requestData.GetRequest()
  88. _ = json.Unmarshal(ret, &appletsOpenRes)
  89. return appletsOpenRes, nil
  90. }
  91. // WeChatJsPay 微信公众号jsapi支付信息
  92. func (wx *WeChatServer) WeChatJsPay(orderSn string, payMoney decimal.Decimal, notifyUrl string, boby string, wxOpenid string) {
  93. curlUrl := "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
  94. result := make(map[string]interface{})
  95. amount := make(map[string]interface{})
  96. amount["total"] = payMoney.Mul(decimal.NewFromInt(100)).IntPart()
  97. amount["currency"] = "CNY"
  98. payer := make(map[string]interface{})
  99. payer["openid"] = wxOpenid
  100. result["appid"] = wx.AppId
  101. result["mchid"] = wx.MchId
  102. result["description"] = boby
  103. result["out_trade_no"] = orderSn
  104. result["notify_url"] = notifyUrl
  105. result["amount"] = amount
  106. result["payer"] = payer
  107. body, _ := json.Marshal(result)
  108. fmt.Println("请求信息:", string(body))
  109. res, _ := wx.JsapiPrepay(curlUrl, orderSn, body)
  110. fmt.Println(res)
  111. }
  112. func (wx *WeChatServer) JsapiPrepay(curlUrl string, orderSn string, body []byte) (JsapiPrepayResponse, error) {
  113. //定义返回信息
  114. var jsapiPrepayResponse JsapiPrepayResponse
  115. //解析请求url,主要用于加密请求头信息
  116. reqUrl, err := url.Parse(curlUrl)
  117. if err != nil {
  118. return jsapiPrepayResponse, err
  119. }
  120. //初始化请求
  121. requestData := http.RequestData{}
  122. err = requestData.ConstructRequest(curlUrl)
  123. if err != nil {
  124. return jsapiPrepayResponse, err
  125. }
  126. requestData.DataByte = body //请求json信息
  127. //组装请求头
  128. requestData.SetHeader("Accept", "application/json")
  129. var authorization string
  130. authorization, err = buildAuthorization(wx.MchId, orderSn, wx.CertificateSerialNo, wx.privateKeyInfo, "POST", reqUrl.RequestURI(), body)
  131. requestData.SetHeader("Authorization", authorization)
  132. var ret []byte
  133. ret, err = requestData.PostJsonRequest()
  134. if err != nil {
  135. return jsapiPrepayResponse, err
  136. }
  137. fmt.Println(string(ret))
  138. return jsapiPrepayResponse, nil
  139. }
  140. // buildAuthorization 构建请求头中的 Authorization 信息
  141. func buildAuthorization(
  142. mchid string,
  143. orderSn string,
  144. certificateSerialNo string,
  145. privateKey *rsa.PrivateKey,
  146. method string,
  147. canonicalURL string,
  148. body []byte,
  149. ) (string, error) {
  150. const (
  151. SignatureMessageFormat = "%s\n%s\n%d\n%s\n%s\n" // 数字签名原文格式
  152. // HeaderAuthorizationFormat 请求头中的 Authorization 拼接格式
  153. HeaderAuthorizationFormat = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""
  154. )
  155. nonce := utils.Md5Sign(orderSn) //随机字符串
  156. timestamp := time.Now().Unix() //输出当前Unix时间戳
  157. message := fmt.Sprintf(SignatureMessageFormat, method, canonicalURL, timestamp, nonce, body)
  158. signature, err := SignSHA256WithRSA(message, privateKey)
  159. if err != nil {
  160. return "", err
  161. }
  162. authorization := fmt.Sprintf(
  163. HeaderAuthorizationFormat,
  164. mchid, nonce, timestamp, certificateSerialNo, signature,
  165. )
  166. return authorization, nil
  167. }
  168. // LoadPrivateKey 通过私钥的文本内容加载私钥
  169. func LoadPrivateKey(privateKeyStr string) (privateKey *rsa.PrivateKey, err error) {
  170. block, _ := pem.Decode([]byte(privateKeyStr))
  171. if block == nil {
  172. return nil, fmt.Errorf("decode private key err")
  173. }
  174. if block.Type != "PRIVATE KEY" {
  175. return nil, fmt.Errorf("the kind of PEM should be PRVATE KEY")
  176. }
  177. key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  178. if err != nil {
  179. return nil, fmt.Errorf("parse private key err:%s", err.Error())
  180. }
  181. privateKey, ok := key.(*rsa.PrivateKey)
  182. if !ok {
  183. return nil, fmt.Errorf("not a RSA private key")
  184. }
  185. return privateKey, nil
  186. }
  187. // LoadPublicKey 通过公钥的文本内容加载公钥
  188. func LoadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
  189. block, _ := pem.Decode([]byte(publicKeyStr))
  190. if block == nil {
  191. return nil, errors.New("decode public key error")
  192. }
  193. if block.Type != "PUBLIC KEY" {
  194. return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
  195. }
  196. key, err := x509.ParsePKIXPublicKey(block.Bytes)
  197. if err != nil {
  198. return nil, fmt.Errorf("parse public key err:%s", err.Error())
  199. }
  200. publicKey, ok := key.(*rsa.PublicKey)
  201. if !ok {
  202. return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
  203. }
  204. return publicKey, nil
  205. }
  206. // LoadPrivateKeyWithPath 通过私钥的文件路径内容加载私钥
  207. func LoadPrivateKeyWithPath(path string) (privateKey *rsa.PrivateKey, err error) {
  208. privateKeyBytes, err := os.ReadFile(path)
  209. if err != nil {
  210. return nil, fmt.Errorf("read private pem file err:%s", err.Error())
  211. }
  212. return LoadPrivateKey(string(privateKeyBytes))
  213. }
  214. // LoadPublicKeyWithPath 通过公钥的文件路径加载公钥
  215. func LoadPublicKeyWithPath(path string) (publicKey *rsa.PublicKey, err error) {
  216. publicKeyBytes, err := os.ReadFile(path)
  217. if err != nil {
  218. return nil, fmt.Errorf("read certificate pem file err:%s", err.Error())
  219. }
  220. return LoadPublicKey(string(publicKeyBytes))
  221. }
  222. // SignSHA256WithRSA 通过私钥对字符串以 SHA256WithRSA 算法生成签名信息
  223. func SignSHA256WithRSA(source string, privateKey *rsa.PrivateKey) (signature string, err error) {
  224. if privateKey == nil {
  225. return "", fmt.Errorf("private key should not be nil")
  226. }
  227. h := crypto.Hash.New(crypto.SHA256)
  228. _, err = h.Write([]byte(source))
  229. if err != nil {
  230. return "", nil
  231. }
  232. hashed := h.Sum(nil)
  233. signatureByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
  234. if err != nil {
  235. return "", err
  236. }
  237. return base64.StdEncoding.EncodeToString(signatureByte), nil
  238. }