From e4d2070bf5d8a12b77b4a3be30736251c616ad8c Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Tue, 1 Nov 2022 17:23:18 +0800 Subject: [PATCH] v1.5.86 --- doc/wechat_v3.md | 77 +++++++++++++++++++++++++++------------------ release_note.txt | 6 ++-- wechat/v3/cert.go | 11 ++----- wechat/v3/notify.go | 2 +- wechat/v3/sign.go | 13 ++++---- 5 files changed, 60 insertions(+), 49 deletions(-) diff --git a/doc/wechat_v3.md b/doc/wechat_v3.md index be3348c1..4509175e 100644 --- a/doc/wechat_v3.md +++ b/doc/wechat_v3.md @@ -22,22 +22,22 @@ ```go import ( - "github.com/go-pay/gopay/pkg/xlog" - "github.com/go-pay/gopay/wechat/v3" +"github.com/go-pay/gopay/pkg/xlog" +"github.com/go-pay/gopay/wechat/v3" ) // NewClientV3 初始化微信客户端 v3 -// mchid:商户ID 或者服务商模式的 sp_mchid -// serialNo:商户证书的证书序列号 -// apiV3Key:apiV3Key,商户平台获取 -// privateKey:私钥 apiclient_key.pem 读取后的内容 +// mchid:商户ID 或者服务商模式的 sp_mchid +// serialNo:商户证书的证书序列号 +// apiV3Key:apiV3Key,商户平台获取 +// privateKey:私钥 apiclient_key.pem 读取后的内容 client, err = wechat.NewClientV3(MchId, SerialNo, APIv3Key, PrivateKey) if err != nil { - xlog.Error(err) - return +xlog.Error(err) +return } -// 设置微信平台API证书和序列号(如开启自动验签,请忽略此步骤) +// 设置微信平台API证书和序列号(推荐开启自动验签,无需手动设置证书公钥等信息) //client.SetPlatformCert([]byte(""), "") // 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号) @@ -111,7 +111,7 @@ app, err := client.PaySignOfApp("appid", "prepayid") jsapi, err := client.PaySignOfJSAPI("appid", "prepayid") ``` -### 4、同步返回参数验签Sign、异步通知参数解析和验签Sign、异步通知返回 +### 4、同步请求返回验签Sign、异步通知参数解析+验签Sign+回执、敏感信息加/解密 > 异步通知请求参数需要先解析,解析出来的结构体或BodyMap再验签(此处需要注意,`http.Request.Body` 只能解析一次,如果需要解析前调试,请处理好Body复用问题) @@ -119,28 +119,30 @@ jsapi, err := client.PaySignOfJSAPI("appid", "prepayid") [Echo Web框架](https://github.com/labstack/echo) -- 同步返回验签,手动验签(如已开启自动验签,则无需手动验签操作) +- ~~同步返回验签,手动验签~~(推荐开启自动验签,则无需手动验签操作) ```go import ( - "github.com/go-pay/gopay/wechat/v3" - "github.com/go-pay/gopay/pkg/xlog" +"github.com/go-pay/gopay/wechat/v3" +"github.com/go-pay/gopay/pkg/xlog" ) wxRsp, err := client.V3TransactionJsapi(bm) if err != nil { - xlog.Error(err) - return +xlog.Error(err) +return } -// wxPublicKey 通过 client.WxPublicKey() 获取 -err = wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, wxPublicKey) + +pkMap := client.WxPublicKeyMap() +// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKeyMap() 获取,然后根据 signInfo.HeaderSerial 获取相应的公钥 +err = wechat.V3VerifySignByPK(wxRsp.SignInfo.HeaderTimestamp, wxRsp.SignInfo.HeaderNonce, wxRsp.SignInfo.SignBody, wxRsp.SignInfo.HeaderSignature, pkMap[wxRsp.SignInfo.HeaderSerial]) if err != nil { - xlog.Error(err) - return +xlog.Error(err) +return } ``` -- 异步通知验签 及 敏感参数解密 +- 异步通知解析、验签、回执 ```go import ( @@ -163,15 +165,7 @@ xlog.Error(err) return } -// ========异步通知敏感信息解密======== -// 普通支付通知解密 -result, err := notifyReq.DecryptCipherText(apiV3Key) -// 合单支付通知解密 -result, err := notifyReq.DecryptCombineCipherText(apiV3Key) -// 退款通知解密 -result, err := notifyReq.DecryptRefundCipherText(apiV3Key) - -// ========异步通知应答======== +// ====↓↓↓====异步通知应答====↓↓↓==== // 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功,否则会重试。 // 注意:重试过多会导致微信支付端积压过多通知而堵塞,影响其他正常通知。 @@ -182,11 +176,31 @@ c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功" return c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"}) ``` +- 敏感信息加/解密 + +```go +// ====↓↓↓====入参、出参加解密====↓↓↓==== + +// 敏感信息加密 +client.V3EncryptText() +// 敏感信息解密 +client.V3DecryptText() + +// ====↓↓↓====异步通知参数解密====↓↓↓==== + +// 普通支付通知解密 +result, err := notifyReq.DecryptCipherText(apiV3Key) +// 合单支付通知解密 +result, err := notifyReq.DecryptCombineCipherText(apiV3Key) +// 退款通知解密 +result, err := notifyReq.DecryptRefundCipherText(apiV3Key) +``` + ### 5、微信v3 公共API(仅部分说明) ```go import ( - "github.com/go-pay/gopay/wechat/v3" +"github.com/go-pay/gopay/wechat/v3" ) // 获取微信平台证书和序列号信息,推荐使用后者 @@ -413,7 +427,8 @@ wechat.V3DecryptScoreNotifyCipherText() * `wechat.GetPlatformCerts()` => 获取微信平台证书公钥 * `client.GetAndSelectNewestCert()` => 获取并选择最新的有效证书 -* `client.WxPublicKeyMap()` => 获取并选择最新的有效证书 Map +* `client.WxPublicKey()` => 获取最新的有效证书 +* `client.WxPublicKeyMap()` => 获取有效证书 Map * `wechat.V3ParseNotify()` => 解析微信回调请求的参数到 V3NotifyReq 结构体 * `notify.VerifySignByPKMap()` => 微信V3 异步通知验签 * `client.V3EncryptText()` => 敏感参数信息加密 diff --git a/release_note.txt b/release_note.txt index cd973d34..9eef35be 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1,8 +1,8 @@ 版本号:Release 1.5.86 修改记录: - (1) 微信V3:新增优化异步验签方法,client.WxPublicKeyMap(),v3NotifyReq.VerifySignByPKMap()。 - (2) 支付宝:修复 app_auth_token 的问题。 - (3) apple:新增接口,Get Transaction History,GetAllSubscriptionStatuses,未真实场景测试。 + (1) 微信V3:优化异步验签方法,v3NotifyReq.VerifySignByPKMap(),通过证书Map自动选择相应的证书验签。 + (2) 微信V3:微信平台证书获取方法变更,client.WxPublicKey() 获取最新微信平台证书;client.WxPublicKeyMap(),获取微信平台证书Map。 + (3) 支付宝:修复 app_auth_token 的问题。 版本号:Release 1.5.85 修改记录: diff --git a/wechat/v3/cert.go b/wechat/v3/cert.go index 4f1be938..12e19b30 100644 --- a/wechat/v3/cert.go +++ b/wechat/v3/cert.go @@ -128,14 +128,9 @@ func (c *ClientV3) SetPlatformCert(wxPublicKeyContent []byte, wxSerialNo string) return c } -// Deprecated -// 推荐使用:client.WxPublicKeyMap() -// 获取 微信平台证书(readonly、disordered) -func (c *ClientV3) WxPublicKey() (wxPublicKey []*rsa.PublicKey) { - for _, v := range c.SnCertMap { - wxPublicKey = append(wxPublicKey, v) - } - return +// 获取最新的 微信平台证书 +func (c *ClientV3) WxPublicKey() (wxPublicKey *rsa.PublicKey) { + return c.wxPublicKey } // 获取 微信平台证书 Map(readonly) diff --git a/wechat/v3/notify.go b/wechat/v3/notify.go index 212819cb..0027cdb1 100644 --- a/wechat/v3/notify.go +++ b/wechat/v3/notify.go @@ -198,7 +198,7 @@ func (v *V3NotifyReq) VerifySign(wxPkContent string) (err error) { } // 异步通知验签 -// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKeyMap() 获取后,取Serial相应的 微信平台公钥 +// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKeyMap() 获取,然后根据 signInfo.HeaderSerial 获取相应的公钥 // 推荐使用 VerifySignByPKMap() func (v *V3NotifyReq) VerifySignByPK(wxPublicKey *rsa.PublicKey) (err error) { if v.SignInfo != nil { diff --git a/wechat/v3/sign.go b/wechat/v3/sign.go index 43357870..6146987d 100644 --- a/wechat/v3/sign.go +++ b/wechat/v3/sign.go @@ -18,7 +18,7 @@ import ( ) // Deprecated -// 推荐使用 wechat.V3VerifySignByPK() +// 推荐使用 wechat.V3VerifySignByPK() func V3VerifySign(timestamp, nonce, signBody, sign, wxPubKeyContent string) (err error) { publicKey, err := xpem.DecodePublicKey([]byte(wxPubKeyContent)) if err != nil { @@ -35,8 +35,9 @@ func V3VerifySign(timestamp, nonce, signBody, sign, wxPubKeyContent string) (err return nil } -// 微信V3 版本验签(同步/异步) -// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKey() 获取 +// 推荐直接开启自动同步验签功能 +// 微信V3 版本验签(同步) +// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKeyMap() 获取,然后根据 signInfo.HeaderSerial 获取相应的公钥 func V3VerifySignByPK(timestamp, nonce, signBody, sign string, wxPublicKey *rsa.PublicKey) (err error) { str := timestamp + "\n" + nonce + "\n" + signBody + "\n" signBytes, _ := base64.StdEncoding.DecodeString(sign) @@ -50,7 +51,7 @@ func V3VerifySignByPK(timestamp, nonce, signBody, sign string, wxPublicKey *rsa. } // PaySignOfJSAPI 获取 JSAPI paySign -// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml +// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml func (c *ClientV3) PaySignOfJSAPI(appid, prepayid string) (jsapi *JSAPIPayParams, err error) { ts := util.Int642String(time.Now().Unix()) nonceStr := util.RandomString(32) @@ -74,7 +75,7 @@ func (c *ClientV3) PaySignOfJSAPI(appid, prepayid string) (jsapi *JSAPIPayParams } // PaySignOfApp 获取 App sign -// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml +// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml func (c *ClientV3) PaySignOfApp(appid, prepayid string) (app *AppPayParams, err error) { ts := util.Int642String(time.Now().Unix()) nonceStr := util.RandomString(32) @@ -98,7 +99,7 @@ func (c *ClientV3) PaySignOfApp(appid, prepayid string) (app *AppPayParams, err } // PaySignOfApplet 获取 小程序 paySign -// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml +// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml func (c *ClientV3) PaySignOfApplet(appid, prepayid string) (applet *AppletParams, err error) { jsapi, err := c.PaySignOfJSAPI(appid, prepayid) if err != nil {