Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
iGoogle-ink committed Mar 8, 2021
1 parent 37b512e commit a2155ba
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 206 deletions.
63 changes: 55 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func main() {

---

### 微信支付API(现已支持部分V3接口,使用方法参考下面介绍或源码)
### 微信支付V2 API(现已支持V3接口,推荐使用V3接口,使用方法参考下面介绍或源码)

> #### 希望有时间的伙伴儿Fork完后,积极提Pull Request,一起完善微信各个类别下的接口到相应的go文件中
Expand Down Expand Up @@ -84,7 +84,7 @@ func main() {
* 查询红包记录:client.QueryRedRecord()
* 自定义方法请求微信API接口:client.PostWeChatAPISelf()

### 微信公共API
### 微信公共V2 API

* wechat.GetParamSign() => 获取微信支付所需参数里的Sign值(通过支付参数计算Sign值)
* wechat.GetSanBoxParamSign() => 获取微信支付沙箱环境所需参数里的Sign值(通过支付参数计算Sign值)
Expand Down Expand Up @@ -205,7 +205,7 @@ QQ群:

## 1、初始化GoPay客户端并做配置(HTTP请求均默认设置tls.Config{InsecureSkipVerify: true})

* #### 微信V3
* #### 微信V3(推荐)

> 注意:V3 版本接口持续增加中,并未做沙箱支付,测试请用1分钱测试法
Expand Down Expand Up @@ -378,7 +378,35 @@ bm.Set("subject", "手机网站测试支付").

## 3、client 方法调用

* #### 微信 client
* #### 微信V3 client(推荐)

```go
// 直连商户
wxRsp, err := client.V3TransactionApp(bm)
wxRsp, err := client.V3TransactionJsapi(bm)
wxRsp, err := client.V3TransactionNative(bm)
wxRsp, err := client.V3TransactionH5(bm)
wxRsp, err := client.V3TransactionQueryOrder(bm)
wxRsp, err := client.V3TransactionCloseOrder(bm)

// 服务商
wxRsp, err := client.V3PartnerTransactionApp(bm)
wxRsp, err := client.V3PartnerTransactionJsapi(bm)
wxRsp, err := client.V3PartnerTransactionNative(bm)
wxRsp, err := client.V3PartnerTransactionH5(bm)
wxRsp, err := client.V3PartnerQueryOrder(bm)
wxRsp, err := client.V3PartnerCloseOrder(bm)

// 合单
wxRsp, err := client.V3CombineTransactionApp(bm)
wxRsp, err := client.V3CombineTransactionJsapi(bm)
wxRsp, err := client.V3CombineTransactionNative(bm)
wxRsp, err := client.V3CombineTransactionH5(bm)
wxRsp, err := client.V3CombineQueryOrder(bm)
wxRsp, err := client.V3CombineCloseOrder(bm)
```

* #### 微信V2 client

```go
wxRsp, err := client.UnifiedOrder(bm)
Expand Down Expand Up @@ -434,13 +462,32 @@ aliRsp, err := client.UserCertifyOpenQuery(bm)

## 4、微信统一下单后,获取微信小程序支付、APP支付、微信内H5支付所需要的 paySign

* #### 微信(只有微信需要此操作)
* #### 微信V3(推荐)

小程序调起支付API:[小程序调起支付API](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml)

APP调起支付API:[APP调起支付API](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml)

JSAPI调起支付API:[JSAPI调起支付API](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml)

H5调起支付API:[H5调起支付API](https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_4.shtml)

```go
// jsapi
jsapi, err := client.PaySignOfJSAPI("prepayid")
// app
app, err := client.PaySignOfApp("prepayid")
// 小程序
applet, err := client.PaySignOfApplet("prepayid")
```

* #### 微信V2

微信小程序支付官方文档:[微信小程序支付API](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html)

APP支付官方文档:[APP端调起支付的参数列表文档](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12)

微信内H5支付官方文档:[微信内H5支付文档](https://pay.weixin.qq.com/wiki/doc/api/external/jsapi.php?chapter=7_7&index=6)
微信内H5支付官方文档:[微信内H5支付文档](https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/pay/OfficialPayMent/chapter5_5.shtml)

```go
import (
Expand Down Expand Up @@ -495,7 +542,7 @@ paySign := wechat.GetH5PaySign(AppID, wxRsp.NonceStr, packages, wechat.SignType_

异步通知处理完后,需回复平台固定数据

* #### 微信V3
* #### 微信V3(推荐)

```go
import (
Expand Down Expand Up @@ -618,7 +665,7 @@ c.String(http.StatusOK, "%s", "success") // 此写法是 gin 框架返回支

## 6、微信、支付宝 公共API(仅部分说明)

* #### 微信 公共API
* #### 微信V2 公共API

官方文档:[code2Session](https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html)

Expand Down
2 changes: 1 addition & 1 deletion wechat/base_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestClient_UnifiedOrder(t *testing.T) {

// 获取H5支付需要的paySign
pac := "prepay_id=" + wxRsp.PrepayId
paySign := GetH5PaySign(appId, wxRsp.NonceStr, pac, SignType_MD5, timeStamp, apiKey)
paySign := GetJsapiPaySign(appId, wxRsp.NonceStr, pac, SignType_MD5, timeStamp, apiKey)
xlog.Debug("paySign:", paySign)

// 获取小程序需要的paySign
Expand Down
193 changes: 0 additions & 193 deletions wechat/payment_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,16 @@ package wechat
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"hash"
"io"
"io/ioutil"
"net/http"
"reflect"
"strings"

"github.com/iGoogle-ink/gopay"
Expand All @@ -30,57 +26,6 @@ import (
"github.com/iGoogle-ink/gopay/pkg/xhttp"
)

// GetParamSign 获取微信支付所需参数里的Sign值(通过支付参数计算Sign值)
// 注意:BodyMap中如无 sign_type 参数,默认赋值 sign_type 为 MD5
// appId:应用ID
// mchId:商户ID
// ApiKey:API秘钥值
// 返回参数 sign:通过Appid、MchId、ApiKey和BodyMap中的参数计算出的Sign值
func GetParamSign(appId, mchId, apiKey string, bm gopay.BodyMap) (sign string) {
bm.Set("appid", appId)
bm.Set("mch_id", mchId)
var (
signType string
h hash.Hash
)
signType = bm.GetString("sign_type")
if signType == util.NULL {
bm.Set("sign_type", SignType_MD5)
}
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}

// GetSanBoxParamSign 获取微信支付沙箱环境所需参数里的Sign值(通过支付参数计算Sign值)
// 注意:沙箱环境默认 sign_type 为 MD5
// appId:应用ID
// mchId:商户ID
// ApiKey:API秘钥值
// 返回参数 sign:通过Appid、MchId、ApiKey和BodyMap中的参数计算出的Sign值
func GetSanBoxParamSign(appId, mchId, apiKey string, bm gopay.BodyMap) (sign string, err error) {
bm.Set("appid", appId)
bm.Set("mch_id", mchId)
bm.Set("sign_type", SignType_MD5)
bm.Set("total_fee", 101)
var (
sandBoxApiKey string
hashMd5 hash.Hash
)
if sandBoxApiKey, err = getSanBoxKey(mchId, util.GetRandomString(32), apiKey, SignType_MD5); err != nil {
return
}
hashMd5 = md5.New()
hashMd5.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
sign = strings.ToUpper(hex.EncodeToString(hashMd5.Sum(nil)))
return
}

// ParseNotifyToBodyMap 解析微信支付异步通知的结果到BodyMap(推荐)
// req:*http.Request
// 返回参数bm:Notify请求的参数
Expand Down Expand Up @@ -179,37 +124,6 @@ func DecryptRefundNotifyReqInfo(reqInfo, apiKey string) (refundNotify *RefundNot
return
}

// VerifySign 微信同步返回参数验签或异步通知参数验签
// ApiKey:API秘钥值
// signType:签名类型(调用API方法时填写的类型)
// bean:微信同步返回的结构体 wxRsp 或 异步通知解析的结构体 notifyReq,推荐通 BodyMap 验签
// 返回参数ok:是否验签通过
// 返回参数err:其他错误信息,不要根据 error 是否为空来判断验签正确与否,需再单独判断返回的 ok
func VerifySign(apiKey, signType string, bean interface{}) (ok bool, err error) {
if bean == nil {
return false, errors.New("bean is nil")
}
kind := reflect.ValueOf(bean).Kind()
if kind == reflect.Map {
bm := bean.(gopay.BodyMap)
bodySign := bm.GetString("sign")
bm.Remove("sign")
return getReleaseSign(apiKey, signType, bm) == bodySign, nil
}

bs, err := json.Marshal(bean)
if err != nil {
return false, fmt.Errorf("json.Marshal(%s):%w", string(bs), err)
}
bm := make(gopay.BodyMap)
if err = json.Unmarshal(bs, &bm); err != nil {
return false, fmt.Errorf("json.Marshal(%s):%w", string(bs), err)
}
bodySign := bm.GetString("sign")
bm.Remove("sign")
return getReleaseSign(apiKey, signType, bm) == bodySign, nil
}

type NotifyResponse struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
Expand All @@ -228,113 +142,6 @@ func (w *NotifyResponse) ToXmlString() (xmlStr string) {
return
}

// GetMiniPaySign JSAPI支付,统一下单获取支付参数后,再次计算出小程序用的paySign
// appId:APPID
// nonceStr:随即字符串
// packages:统一下单成功后拼接得到的值
// signType:签名类型
// timeStamp:时间
// ApiKey:API秘钥值
// 微信小程序支付API:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html
// 微信小程序支付PaySign计算文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
func GetMiniPaySign(appId, nonceStr, packages, signType, timeStamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appId=")
buffer.WriteString(appId)
buffer.WriteString("&nonceStr=")
buffer.WriteString(nonceStr)
buffer.WriteString("&package=")
buffer.WriteString(packages)
buffer.WriteString("&signType=")
buffer.WriteString(signType)
buffer.WriteString("&timeStamp=")
buffer.WriteString(timeStamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}

// GetH5PaySign 微信内H5支付,统一下单获取支付参数后,再次计算出微信内H5支付需要用的paySign
// appId:APPID
// nonceStr:随即字符串
// packages:统一下单成功后拼接得到的值
// signType:签名类型
// timeStamp:时间
// ApiKey:API秘钥值
// 微信内H5支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/pay/OfficialPayMent/chapter5_5.shtml
func GetH5PaySign(appId, nonceStr, packages, signType, timeStamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appId=")
buffer.WriteString(appId)
buffer.WriteString("&nonceStr=")
buffer.WriteString(nonceStr)
buffer.WriteString("&package=")
buffer.WriteString(packages)
buffer.WriteString("&signType=")
buffer.WriteString(signType)
buffer.WriteString("&timeStamp=")
buffer.WriteString(timeStamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
paySign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}

// GetAppPaySign APP支付,统一下单获取支付参数后,再次计算APP支付所需要的的sign
// appId:APPID
// partnerid:partnerid
// nonceStr:随即字符串
// prepayId:统一下单成功后得到的值
// signType:此处签名方式,务必与统一下单时用的签名方式一致
// timeStamp:时间
// ApiKey:API秘钥值
// APP支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
func GetAppPaySign(appid, partnerid, noncestr, prepayid, signType, timestamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appid=")
buffer.WriteString(appid)
buffer.WriteString("&noncestr=")
buffer.WriteString(noncestr)
buffer.WriteString("&package=Sign=WXPay")
buffer.WriteString("&partnerid=")
buffer.WriteString(partnerid)
buffer.WriteString("&prepayid=")
buffer.WriteString(prepayid)
buffer.WriteString("&timestamp=")
buffer.WriteString(timestamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
paySign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}

// DecryptOpenDataToBodyMap 解密开放数据到 BodyMap
// encryptedData:包括敏感数据在内的完整用户信息的加密数据,小程序获取到
// iv:加密算法的初始向量,小程序获取到
Expand Down
Loading

0 comments on commit a2155ba

Please sign in to comment.