wechat_servier_api.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. //==================================
  2. // * Name:Jerry
  3. // * DateTime:2019/5/6 13:16
  4. // * Desc:
  5. //==================================
  6. package gopay
  7. import (
  8. "bytes"
  9. "crypto/aes"
  10. "crypto/cipher"
  11. "crypto/hmac"
  12. "crypto/md5"
  13. "crypto/sha256"
  14. "crypto/tls"
  15. "encoding/base64"
  16. "encoding/hex"
  17. "encoding/json"
  18. "errors"
  19. "github.com/parnurzeal/gorequest"
  20. "reflect"
  21. "strings"
  22. )
  23. func HttpAgent() (agent *gorequest.SuperAgent) {
  24. agent = gorequest.New()
  25. agent.TLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  26. return
  27. }
  28. //验证支付成功后通知Sign值
  29. func VerifyPayResultSign(apiKey string, notifyRsp *WeChatNotifyRequest) (ok bool, sign string) {
  30. body := make(BodyMap)
  31. body.Set("return_code", notifyRsp.ReturnCode)
  32. body.Set("return_msg", notifyRsp.ReturnMsg)
  33. body.Set("appid", notifyRsp.Appid)
  34. body.Set("mch_id", notifyRsp.MchId)
  35. body.Set("device_info", notifyRsp.DeviceInfo)
  36. body.Set("nonce_str", notifyRsp.NonceStr)
  37. body.Set("sign_type", notifyRsp.SignType)
  38. body.Set("result_code", notifyRsp.ResultCode)
  39. body.Set("err_code", notifyRsp.ErrCode)
  40. body.Set("err_code_des", notifyRsp.ErrCodeDes)
  41. body.Set("openid", notifyRsp.Openid)
  42. body.Set("is_subscribe", notifyRsp.IsSubscribe)
  43. body.Set("trade_type", notifyRsp.TradeType)
  44. body.Set("bank_type", notifyRsp.BankType)
  45. body.Set("total_fee", notifyRsp.TotalFee)
  46. body.Set("settlement_total_fee", notifyRsp.SettlementTotalFee)
  47. body.Set("fee_type", notifyRsp.FeeType)
  48. body.Set("cash_fee", notifyRsp.CashFee)
  49. body.Set("cash_fee_type", notifyRsp.CashFeeType)
  50. body.Set("coupon_fee", notifyRsp.CouponFee)
  51. body.Set("coupon_count", notifyRsp.CouponCount)
  52. body.Set("coupon_type_0", notifyRsp.CouponType0)
  53. body.Set("coupon_id_0", notifyRsp.CouponId0)
  54. body.Set("coupon_fee_$n", notifyRsp.CouponFee0)
  55. body.Set("transaction_id", notifyRsp.TransactionId)
  56. body.Set("out_trade_no", notifyRsp.OutTradeNo)
  57. body.Set("attach", notifyRsp.Attach)
  58. body.Set("time_end", notifyRsp.TimeEnd)
  59. signStr := sortSignParams(apiKey, body)
  60. var hashSign []byte
  61. if notifyRsp.SignType == SignType_MD5 {
  62. hash := md5.New()
  63. hash.Write([]byte(signStr))
  64. hashSign = hash.Sum(nil)
  65. } else {
  66. hash := hmac.New(sha256.New, []byte(apiKey))
  67. hash.Write([]byte(signStr))
  68. hashSign = hash.Sum(nil)
  69. }
  70. sign = strings.ToUpper(hex.EncodeToString(hashSign))
  71. ok = sign == notifyRsp.SignType
  72. return
  73. }
  74. //JSAPI支付,支付参数后,再次计算出小程序用的paySign
  75. func GetMiniPaySign(appId, nonceStr, prepayId, signType, timeStamp, apiKey string) (paySign string) {
  76. buffer := new(bytes.Buffer)
  77. buffer.WriteString("appId=")
  78. buffer.WriteString(appId)
  79. buffer.WriteString("&nonceStr=")
  80. buffer.WriteString(nonceStr)
  81. buffer.WriteString("&package=")
  82. buffer.WriteString(prepayId)
  83. buffer.WriteString("&signType=")
  84. buffer.WriteString(signType)
  85. buffer.WriteString("&timeStamp=")
  86. buffer.WriteString(timeStamp)
  87. buffer.WriteString("&key=")
  88. buffer.WriteString(apiKey)
  89. signStr := buffer.String()
  90. var hashSign []byte
  91. if signType == SignType_MD5 {
  92. hash := md5.New()
  93. hash.Write([]byte(signStr))
  94. hashSign = hash.Sum(nil)
  95. } else {
  96. hash := hmac.New(sha256.New, []byte(apiKey))
  97. hash.Write([]byte(signStr))
  98. hashSign = hash.Sum(nil)
  99. }
  100. paySign = strings.ToUpper(hex.EncodeToString(hashSign))
  101. return
  102. }
  103. //JSAPI支付,支付参数后,再次计算出微信内H5支付需要用的paySign
  104. func GetH5PaySign(appId, nonceStr, prepayId, signType, timeStamp, apiKey string) (paySign string) {
  105. buffer := new(bytes.Buffer)
  106. buffer.WriteString("appId=")
  107. buffer.WriteString(appId)
  108. buffer.WriteString("&nonceStr=")
  109. buffer.WriteString(nonceStr)
  110. buffer.WriteString("&package=")
  111. buffer.WriteString(prepayId)
  112. buffer.WriteString("&signType=")
  113. buffer.WriteString(signType)
  114. buffer.WriteString("&timeStamp=")
  115. buffer.WriteString(timeStamp)
  116. buffer.WriteString("&key=")
  117. buffer.WriteString(apiKey)
  118. signStr := buffer.String()
  119. var hashSign []byte
  120. if signType == SignType_MD5 {
  121. hash := md5.New()
  122. hash.Write([]byte(signStr))
  123. hashSign = hash.Sum(nil)
  124. } else {
  125. hash := hmac.New(sha256.New, []byte(apiKey))
  126. hash.Write([]byte(signStr))
  127. hashSign = hash.Sum(nil)
  128. }
  129. paySign = strings.ToUpper(hex.EncodeToString(hashSign))
  130. return
  131. }
  132. //解密开放数据
  133. // encryptedData:包括敏感数据在内的完整用户信息的加密数据
  134. // iv:加密算法的初始向量
  135. // sessionKey:会话密钥
  136. // beanPtr:需要解析到的结构体指针
  137. func DecryptOpenDataToStruct(encryptedData, iv, sessionKey string, beanPtr interface{}) (err error) {
  138. //验证参数类型
  139. beanValue := reflect.ValueOf(beanPtr)
  140. if beanValue.Kind() != reflect.Ptr {
  141. return errors.New("传入beanPtr类型必须是以指针形式")
  142. }
  143. //验证interface{}类型
  144. if beanValue.Elem().Kind() != reflect.Struct {
  145. return errors.New("传入interface{}必须是结构体")
  146. }
  147. aesKey, _ := base64.StdEncoding.DecodeString(sessionKey)
  148. ivKey, _ := base64.StdEncoding.DecodeString(iv)
  149. cipherText, _ := base64.StdEncoding.DecodeString(encryptedData)
  150. if len(cipherText)%len(aesKey) != 0 {
  151. return errors.New("encryptedData is error")
  152. }
  153. //fmt.Println("cipherText:", cipherText)
  154. block, err := aes.NewCipher(aesKey)
  155. if err != nil {
  156. return err
  157. }
  158. //解密
  159. blockMode := cipher.NewCBCDecrypter(block, ivKey)
  160. plainText := make([]byte, len(cipherText))
  161. blockMode.CryptBlocks(plainText, cipherText)
  162. //fmt.Println("plainText1:", plainText)
  163. plainText = PKCS7UnPadding(plainText)
  164. //fmt.Println("plainText:", plainText)
  165. //解析
  166. err = json.Unmarshal(plainText, beanPtr)
  167. if err != nil {
  168. return err
  169. }
  170. return nil
  171. }
  172. //获取微信用户的OpenId、SessionKey、UnionId
  173. // appId:APPID
  174. // appSecret:AppSecret
  175. // wxCode:小程序调用wx.login 获取的code
  176. func Code2Session(appId, appSecret, wxCode string) (sessionRsp *Code2SessionRsp, err error) {
  177. sessionRsp = new(Code2SessionRsp)
  178. url := "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + wxCode + "&grant_type=authorization_code"
  179. agent := HttpAgent()
  180. _, _, errs := agent.Get(url).EndStruct(sessionRsp)
  181. if len(errs) > 0 {
  182. return nil, errs[0]
  183. } else {
  184. return sessionRsp, nil
  185. }
  186. }
  187. //获取小程序全局唯一后台接口调用凭据(AccessToken:157字符)
  188. // appId:APPID
  189. // appSecret:AppSecret
  190. func GetAccessToken(appId, appSecret string) (accessToken *AccessToken, err error) {
  191. accessToken = new(AccessToken)
  192. url := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret
  193. agent := HttpAgent()
  194. _, _, errs := agent.Get(url).EndStruct(accessToken)
  195. if len(errs) > 0 {
  196. return nil, errs[0]
  197. } else {
  198. return accessToken, nil
  199. }
  200. }
  201. //用户支付完成后,获取该用户的 UnionId,无需用户授权。
  202. // accessToken:接口调用凭据
  203. // openId:用户的OpenID
  204. // transactionId:微信支付订单号
  205. func GetPaidUnionId(accessToken, openId, transactionId string) (unionId *PaidUnionId, err error) {
  206. unionId = new(PaidUnionId)
  207. url := "https://api.weixin.qq.com/wxa/getpaidunionid?access_token=" + accessToken + "&openid=" + openId + "&transaction_id=" + transactionId
  208. agent := HttpAgent()
  209. _, _, errs := agent.Get(url).EndStruct(unionId)
  210. if len(errs) > 0 {
  211. return nil, errs[0]
  212. } else {
  213. return unionId, nil
  214. }
  215. }
  216. //获取用户基本信息(UnionID机制)
  217. // accessToken:接口调用凭据
  218. // openId:用户的OpenID
  219. // lang:默认为 zh_CN ,可选填 zh_CN 简体,zh_TW 繁体,en 英语
  220. func GetWeChatUserInfo(accessToken, openId string, lang ...string) (userInfo *WeChatUserInfo, err error) {
  221. userInfo = new(WeChatUserInfo)
  222. var url string
  223. if len(lang) > 0 {
  224. url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId + "&lang=" + lang[0]
  225. } else {
  226. url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN"
  227. }
  228. agent := HttpAgent()
  229. _, _, errs := agent.Get(url).EndStruct(userInfo)
  230. if len(errs) > 0 {
  231. return nil, errs[0]
  232. } else {
  233. return userInfo, nil
  234. }
  235. }