From 99402213fc2cc97df218a24fc5111998c32d8dfd Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Mon, 2 Dec 2024 14:08:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1v3=20?= =?UTF-8?q?=E7=9A=84=E6=8E=8C=E7=BA=B9=E6=94=AF=E4=BB=98=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20(#433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * map to smap * 增加掌纹支付预授权查询接口 --- body_map_test.go | 5 ----- constant.go | 2 +- doc/wechat_v3.md | 3 +++ go.mod | 5 +++-- go.sum | 10 +++++---- release_note.txt | 4 ++++ wechat/v3/cert.go | 17 +++++++-------- wechat/v3/client.go | 17 +++++++-------- wechat/v3/constant.go | 4 ++++ wechat/v3/model.go | 25 ++++++++++++++++++++++ wechat/v3/palm.go | 49 +++++++++++++++++++++++++++++++++++++++++++ wechat/v3/sign.go | 9 +++----- 12 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 wechat/v3/palm.go diff --git a/body_map_test.go b/body_map_test.go index 22db6d44..48c451a3 100644 --- a/body_map_test.go +++ b/body_map_test.go @@ -1,7 +1,6 @@ package gopay import ( - "container/list" "encoding/json" "encoding/xml" "testing" @@ -173,7 +172,3 @@ func TestOutSlice(t *testing.T) { xlog.Debugf("%s", bm.GetString("")) xlog.Debugf("%s", bm.JsonBody()) } - -func TestLruCache(t *testing.T) { - list.New() -} diff --git a/constant.go b/constant.go index 8ccd77f0..eac7463a 100644 --- a/constant.go +++ b/constant.go @@ -7,7 +7,7 @@ const ( OK = "OK" DebugOff = 0 DebugOn = 1 - Version = "v1.5.106" + Version = "v1.5.107" ) type DebugSwitch int8 diff --git a/doc/wechat_v3.md b/doc/wechat_v3.md index 374a662b..da50550b 100644 --- a/doc/wechat_v3.md +++ b/doc/wechat_v3.md @@ -445,6 +445,9 @@ wechat.V3DecryptCombineNotifyCipherText() * 查询省份列表:`client.V3BankSearchProvinceList()` * 查询城市列表:`client.V3BankSearchCityList()` * 查询支行列表:`client.V3BankSearchBranchList()` +* 掌纹支付 + * 用户自主录掌&预授权:`client.V3PalmServicePreAuthorize()` + * 预授权状态查询:`client.V3PalmServiceOpenidQuery()` ### 微信v3公共 API diff --git a/go.mod b/go.mod index c1adf547..f7290243 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,10 @@ go 1.21 require ( github.com/go-pay/crypto v0.0.1 - github.com/go-pay/errgroup v0.0.2 + github.com/go-pay/errgroup v0.0.3 + github.com/go-pay/smap v0.0.2 github.com/go-pay/util v0.0.4 github.com/go-pay/xlog v0.0.3 github.com/go-pay/xtime v0.0.2 - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 ) diff --git a/go.sum b/go.sum index 87daf68b..c7310517 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,14 @@ github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY= github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes= -github.com/go-pay/errgroup v0.0.2 h1:5mZMdm0TDClDm2S3G0/sm0f8AuQRtz0dOrTHDR9R8Cc= -github.com/go-pay/errgroup v0.0.2/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8= +github.com/go-pay/errgroup v0.0.3 h1:DB4s8e8oWYDyETKQ1y1riMJ7y29zE1uIsMCSjEOFSbU= +github.com/go-pay/errgroup v0.0.3/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8= +github.com/go-pay/smap v0.0.2 h1:kKflYor5T5FgZltPFBMTFfjJvqYMHr5VnIFSEyhVTcA= +github.com/go-pay/smap v0.0.2/go.mod h1:HW9oAo0okuyDYsbpbj5fJFxnNj/BZorRGFw26SxrNWw= github.com/go-pay/util v0.0.4 h1:TuwSU9o3Qd7m9v1PbzFuIA/8uO9FJnA6P7neG/NwPyk= github.com/go-pay/util v0.0.4/go.mod h1:Tsdhs8Ib9J9b4+NKNO1PHh5hWHhlg98PthsX0ckq6PM= github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes= github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw= github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM= github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= diff --git a/release_note.txt b/release_note.txt index ca44fc89..ff99eba4 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1,3 +1,7 @@ +版本号:v1.5.107 +修改记录: + (1) 微信V3:新增掌纹支付相关接口。 + 版本号:v1.5.106 修改记录: (1) 支付宝:支付宝支持V3接口,接口还在完善中,欢迎提PR一起建设。 diff --git a/wechat/v3/cert.go b/wechat/v3/cert.go index 2e319dcf..9b8f7560 100644 --- a/wechat/v3/cert.go +++ b/wechat/v3/cert.go @@ -153,10 +153,11 @@ func (c *ClientV3) WxPublicKey() (wxPublicKey *rsa.PublicKey) { // 获取 微信平台证书 Map(readonly) // wxPublicKeyMap: key:SerialNo, value:WxPublicKey func (c *ClientV3) WxPublicKeyMap() (wxPublicKeyMap map[string]*rsa.PublicKey) { - wxPublicKeyMap = make(map[string]*rsa.PublicKey, len(c.SnCertMap)) - for k, v := range c.SnCertMap { + wxPublicKeyMap = make(map[string]*rsa.PublicKey) + c.SnCertMap.Range(func(k string, v *rsa.PublicKey) bool { wxPublicKeyMap[k] = v - } + return true + }) return wxPublicKeyMap } @@ -328,19 +329,17 @@ func (c *ClientV3) autoCheckCertProc() { if err != nil { return err } - snPkMap := make(map[string]*rsa.PublicKey) for sn, cert := range snCertMap { pubKey, err := xpem.DecodePublicKey([]byte(cert)) if err != nil { return err } - snPkMap[sn] = pubKey + c.SnCertMap.Store(sn, pubKey) + if sn == serialNo { + c.wxPublicKey = pubKey + } } - c.rwMu.Lock() - c.SnCertMap = snPkMap c.WxSerialNo = serialNo - c.wxPublicKey = snPkMap[serialNo] - c.rwMu.Unlock() return nil }, 3, time.Second) if err != nil { diff --git a/wechat/v3/client.go b/wechat/v3/client.go index 93908d62..234b0628 100644 --- a/wechat/v3/client.go +++ b/wechat/v3/client.go @@ -9,6 +9,7 @@ import ( "github.com/go-pay/crypto/xpem" "github.com/go-pay/gopay" "github.com/go-pay/gopay/pkg/xhttp" + "github.com/go-pay/smap" "github.com/go-pay/xlog" ) @@ -27,7 +28,7 @@ type ClientV3 struct { DebugSwitch gopay.DebugSwitch requestIdFunc xhttp.RequestIdHandler logger xlog.XLogger - SnCertMap map[string]*rsa.PublicKey // key: serial_no + SnCertMap smap.Map[string, *rsa.PublicKey] // key: serial_no } // NewClientV3 初始化微信客户端 V3 @@ -72,19 +73,18 @@ func (c *ClientV3) AutoVerifySign(autoRefresh ...bool) (err error) { if err != nil { return err } - if len(c.SnCertMap) <= 0 { - c.SnCertMap = make(map[string]*rsa.PublicKey) - } for sn, cert := range certMap { // decode cert pubKey, err := xpem.DecodePublicKey([]byte(cert)) if err != nil { return err } - c.SnCertMap[sn] = pubKey + c.SnCertMap.Store(sn, pubKey) + if sn == wxSerialNo { + c.wxPublicKey = pubKey + } } c.WxSerialNo = wxSerialNo - c.wxPublicKey = c.SnCertMap[wxSerialNo] if len(autoRefresh) == 1 && !autoRefresh[0] { return nil } @@ -103,10 +103,7 @@ func (c *ClientV3) AutoVerifySignByCert(wxPublicKeyContent []byte, wxPublicKeyID if pubKey == nil { return errors.New("xpem.DecodePublicKey() failed, pubKey is nil") } - if len(c.SnCertMap) <= 0 { - c.SnCertMap = make(map[string]*rsa.PublicKey) - } - c.SnCertMap[wxPublicKeyID] = pubKey + c.SnCertMap.Store(wxPublicKeyID, pubKey) c.wxPublicKey = pubKey c.WxSerialNo = wxPublicKeyID c.autoSign = true diff --git a/wechat/v3/constant.go b/wechat/v3/constant.go index 75738623..43dc7675 100644 --- a/wechat/v3/constant.go +++ b/wechat/v3/constant.go @@ -304,6 +304,10 @@ const ( // 扣款服务-直连模式(其他相关接口在v2接口中) v3EntrustPayNotify = "/v3/papay/contracts/%s/notify" // contract_id 预扣费通知 POST + // 刷掌支付 + v3PalmServicePreAuthorize = "/v3/palmservice/authorization/preauthorize" // 用户自主录掌&预授权 POST + v3PalmServiceOpenidQuery = "/v3/palmservice/authorization/openid/%s" // organization_id 预授权状态查询 GET + // 特约商户进件申请单状态 ApplyStateEditing = "APPLYMENT_STATE_EDITTING" // 编辑中 ApplyStateAuditing = "APPLYMENT_STATE_AUDITING" // 审核中 diff --git a/wechat/v3/model.go b/wechat/v3/model.go index 85ad04be..27bd301a 100644 --- a/wechat/v3/model.go +++ b/wechat/v3/model.go @@ -65,6 +65,20 @@ type EntrustPayNotifyRsp struct { Error string `json:"-"` } +type PalmServicePreAuthorizeRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *PalmServicePreAuthorize `json:"response,omitempty"` + Error string `json:"-"` +} + +type PalmServiceOpenidQueryRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *PalmServiceOpenidQuery `json:"response,omitempty"` + Error string `json:"-"` +} + // =========================================================分割========================================================= type JSAPIPayParams struct { @@ -299,3 +313,14 @@ type WithdrawStatus struct { AccountBank string `json:"account_bank"` // 服务商提现入账的开户银行 BankName string `json:"bank_name"` // 服务商提现入账的开户银行全称(含支行) } + +type PalmServicePreAuthorize struct { + PermissionToken string `json:"permission_token"` // 预授权token,跳转小程序使用 +} + +type PalmServiceOpenidQuery struct { + OrganizationId string `json:"organization_id"` + Openid string `json:"openid"` + State string `json:"state"` + AuthorizeTime string `json:"authorize_time"` +} diff --git a/wechat/v3/palm.go b/wechat/v3/palm.go new file mode 100644 index 00000000..b32f0805 --- /dev/null +++ b/wechat/v3/palm.go @@ -0,0 +1,49 @@ +package wechat + +import ( + "context" + "net/http" + + "github.com/go-pay/gopay" +) + +// 用户自主录掌&预授权 +// Code = 0 is success +func (c *ClientV3) V3PalmServicePreAuthorize(ctx context.Context, bm gopay.BodyMap) (wxRsp *PalmServicePreAuthorizeRsp, err error) { + authorization, err := c.authorization(MethodPost, v3PalmServicePreAuthorize, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3PalmServicePreAuthorize, authorization) + if err != nil { + return nil, err + } + wxRsp = &PalmServicePreAuthorizeRsp{Code: Success, SignInfo: si} + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 预授权状态查询 +// Code = 0 is success +func (c *ClientV3) V3PalmServiceOpenidQuery(ctx context.Context, bm gopay.BodyMap) (wxRsp *PalmServiceOpenidQueryRsp, err error) { + uri := v3PalmServiceOpenidQuery + "?" + bm.EncodeURLParams() + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + wxRsp = &PalmServiceOpenidQueryRsp{Code: Success, SignInfo: si} + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} diff --git a/wechat/v3/sign.go b/wechat/v3/sign.go index ae47cd3a..2a84fce8 100644 --- a/wechat/v3/sign.go +++ b/wechat/v3/sign.go @@ -268,17 +268,14 @@ func (c *ClientV3) verifySyncSign(si *SignInfo) (err error) { if si == nil { return errors.New("auto verify sign, but SignInfo is nil") } - c.rwMu.RLock() - wxPublicKey, exist := c.SnCertMap[si.HeaderSerial] - c.rwMu.RUnlock() + + wxPublicKey, exist := c.SnCertMap.Load(si.HeaderSerial) if !exist { err = c.AutoVerifySign(false) if err != nil { return fmt.Errorf("[get all public key err]: %v", err) } - c.rwMu.RLock() - wxPublicKey, exist = c.SnCertMap[si.HeaderSerial] - c.rwMu.RUnlock() + wxPublicKey, exist = c.SnCertMap.Load(si.HeaderSerial) if !exist { return errors.New("auto verify sign, but public key not found") }