Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
iGoogle-ink committed Jun 28, 2021
1 parent e825e34 commit 5363939
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 36 deletions.
13 changes: 11 additions & 2 deletions wechat/v3/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
// 注意事项
// 如果自行实现验证平台签名逻辑的话,需要注意以下事项:
// - 程序实现定期更新平台证书的逻辑,不要硬编码验证应答消息签名的平台证书
// - 定期调用该接口,间隔时间小于12 小时
// - 定期调用该接口,间隔时间小于12小时
// - 加密请求消息中的敏感信息时,使用最新的平台证书(即:证书启用时间较晚的证书)
// 文档说明:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml
func (c *ClientV3) GetPlatformCerts() (certs *PlatformCertRsp, err error) {
Expand Down Expand Up @@ -72,10 +72,19 @@ func (c *ClientV3) GetPlatformCerts() (certs *PlatformCertRsp, err error) {
return certs, c.verifySyncSign(si)
}

// 设置 微信支付平台证书 和 证书序列号
// 注意:请预先通过 client.GetPlatformCerts() 获取 微信平台证书 和 证书序列号
// 部分接口请求参数中敏感信息加密,使用此 微信支付平台公钥 和 证书序列号
func (c *ClientV3) SetPlatformCert(wxPkContent []byte, wxSerialNo string) (client *ClientV3) {
c.wxPkContent = wxPkContent
c.wxSerialNo = wxSerialNo
return c
}

// 解密加密的证书
func (c *ClientV3) DecryptCerts(ciphertext, nonce, additional string) (wxCerts string, err error) {
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(c.apiV3Key))
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), c.apiV3Key)
if err != nil {
return "", fmt.Errorf("aes.GCMDecrypt, err:%+v", err)
}
Expand Down
28 changes: 14 additions & 14 deletions wechat/v3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ type ClientV3 struct {
Appid string
Mchid string
SerialNo string
apiV3Key string
apiV3Key []byte
wxSerialNo string
wxPkContent []byte
autoSign bool
privateKey *rsa.PrivateKey
Expand All @@ -31,8 +32,8 @@ type ClientV3 struct {
// NewClientV3 初始化微信客户端 V3
// appid:appid 或者服务商模式的 sp_appid
// mchid:商户ID 或者服务商模式的 sp_mchid
// serialNo:商户证书的证书序列号
// apiV3Key:apiV3Key,商户平台获取
// serialNo:商户API证书的证书序列号
// apiV3Key:APIv3Key,商户平台获取
// pkContent:私钥 apiclient_key.pem 读取后的字符串内容
func NewClientV3(appid, mchid, serialNo, apiV3Key, pkContent string) (client *ClientV3, err error) {
var (
Expand Down Expand Up @@ -60,18 +61,17 @@ func NewClientV3(appid, mchid, serialNo, apiV3Key, pkContent string) (client *Cl
Appid: appid,
Mchid: mchid,
SerialNo: serialNo,
apiV3Key: apiV3Key,
apiV3Key: []byte(apiV3Key),
privateKey: pk,
DebugSwitch: gopay.DebugOff,
}
return client, nil
}

// AutoVerifySign 开启请求完自动验签功能(默认不开启,推荐开启)
// 注意:未获取到微信平台公钥时,不要开启,请调用 client.GetPlatformCerts() 获取微信平台证书公钥
func (c *ClientV3) AutoVerifySign(wxPkContent []byte) {
if wxPkContent != nil {
c.wxPkContent = wxPkContent
// 注意:在此方法之前,请先调用 client.SetPlatformCert() 设置微信平台证书和证书序列号,否则不生效
func (c *ClientV3) AutoVerifySign() {
if c.wxPkContent != nil && c.wxSerialNo != "" {
c.autoSign = true
}
}
Expand All @@ -86,7 +86,7 @@ func (c *ClientV3) doProdPost(bm gopay.BodyMap, path, authorization string) (res
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeJSON).Post(url).SendBodyMap(bm).EndBytes()
if len(errs) > 0 {
Expand Down Expand Up @@ -116,7 +116,7 @@ func (c *ClientV3) doProdGet(uri, authorization string) (res *http.Response, si
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeJSON).Get(url).EndBytes()
if len(errs) > 0 {
Expand Down Expand Up @@ -147,7 +147,7 @@ func (c *ClientV3) doProdPut(bm gopay.BodyMap, path, authorization string) (res
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeJSON).Put(url).SendBodyMap(bm).EndBytes()
if len(errs) > 0 {
Expand Down Expand Up @@ -178,7 +178,7 @@ func (c *ClientV3) doProdDelete(bm gopay.BodyMap, path, authorization string) (r
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeJSON).Delete(url).SendBodyMap(bm).EndBytes()
if len(errs) > 0 {
Expand Down Expand Up @@ -208,7 +208,7 @@ func (c *ClientV3) doProdPostFile(bm gopay.BodyMap, path, authorization string)
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeMultipartFormData).Post(url).SendMultipartBodyMap(bm).EndBytes()
if len(errs) > 0 {
Expand Down Expand Up @@ -239,7 +239,7 @@ func (c *ClientV3) doProdPatch(bm gopay.BodyMap, path, authorization string) (re
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
}
httpClient.Header.Add(HeaderAuthorization, authorization)
httpClient.Header.Add(HeaderSerial, c.SerialNo)
httpClient.Header.Add(HeaderSerial, c.wxSerialNo)
httpClient.Header.Add("Accept", "*/*")
res, bs, errs := httpClient.Type(xhttp.TypeJSON).Patch(url).SendBodyMap(bm).EndBytes()
if len(errs) > 0 {
Expand Down
27 changes: 14 additions & 13 deletions wechat/v3/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,32 @@ import (
)

var (
client *ClientV3
err error
Appid = ""
MchId = ""
ApiV3Key = ""
SerialNo = ""
PKContent = ``
WxPkContent = ``
client *ClientV3
err error
Appid = ""
MchId = ""
APIv3Key = ""
SerialNo = ""
PKContent = ``
WxPkSerialNo = ""
WxPkContent = ``
)

func TestMain(m *testing.M) {
// NewClientV3 初始化微信客户端 V3
// appid:appid
// mchid:商户ID
// serialNo:商户证书的证书序列号
// apiV3Key:apiV3Key,商户平台获取
// apiV3Key:APIv3Key,商户平台获取
// pkContent:私钥 apiclient_key.pem 读取后的字符串内容
client, err = NewClientV3(Appid, MchId, SerialNo, ApiV3Key, PKContent)
client, err = NewClientV3(Appid, MchId, SerialNo, APIv3Key, PKContent)
if err != nil {
xlog.Error(err)
return
}
// 自动同步返回验签
// 注意:未获取到微信平台公钥时,不要开启,请调用 client.GetPlatformCerts() 获取微信平台证书公钥
//client.AutoVerifySign(WxPkContent)
// 设置微信平台证书和序列号,并启用自动同步返回验签
// 注意:请预先通过 client.GetPlatformCerts() 获取微信平台证书和证书序列号
client.SetPlatformCert([]byte(WxPkContent), WxPkSerialNo).AutoVerifySign()

// 打开Debug开关,输出日志
client.DebugSwitch = gopay.DebugOff
Expand Down
48 changes: 44 additions & 4 deletions wechat/v3/encrypt_decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,47 @@ import (
)

// 敏感信息加密,默认 PKCS1
func V3EncryptText(text string, rsaPublicKeyContent []byte) (cipherText string, err error) {
block, _ := pem.Decode(rsaPublicKeyContent)
func (c *ClientV3) V3EncryptText(text string) (cipherText string, err error) {
if c.wxPkContent == nil || c.wxSerialNo == "" {
return util.NULL, errors.New("WxPkContent or WxSerialNo is null")
}
block, _ := pem.Decode(c.wxPkContent)
if block == nil {
return util.NULL, errors.New("pem.Decode:wxPkContent decode error")
}
pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("x509.ParsePKCS1PublicKey:%w", err)
}
cipherByte, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, pubKey, []byte(text), nil)
if err != nil {
return "", fmt.Errorf("rsa.EncryptOAEP:%w", err)
}
return base64.StdEncoding.EncodeToString(cipherByte), nil
}

// 敏感信息解密,默认 PKCS1
func (c *ClientV3) V3DecryptText(cipherText string) (text string, err error) {
cipherByte, _ := base64.StdEncoding.DecodeString(cipherText)
block, _ := pem.Decode(c.apiV3Key)
if block == nil {
return util.NULL, errors.New("pem.Decode:apiV3Key decode error")
}
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("x509.ParsePKCS1PrivateKey:%w", err)
}
textByte, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, priKey, cipherByte, nil)
if err != nil {
return "", fmt.Errorf("rsa.DecryptOAEP:%w", err)
}
return string(textByte), nil
}

// 敏感信息加密,默认 PKCS1
// wxPkContent:微信平台证书内容
func V3EncryptText(text string, wxPkContent []byte) (cipherText string, err error) {
block, _ := pem.Decode(wxPkContent)
if block == nil {
return util.NULL, errors.New("pem.Decode:rsaPublicKey decode error")
}
Expand All @@ -33,9 +72,10 @@ func V3EncryptText(text string, rsaPublicKeyContent []byte) (cipherText string,
}

// 敏感信息解密,默认 PKCS1
func V3DecryptText(cipherText string, rsaPrivateKeyContent []byte) (text string, err error) {
// apiV3Key:商户API证书字符串内容,商户平台获取
func V3DecryptText(cipherText string, apiV3Key []byte) (text string, err error) {
cipherByte, _ := base64.StdEncoding.DecodeString(cipherText)
block, _ := pem.Decode(rsaPrivateKeyContent)
block, _ := pem.Decode(apiV3Key)
if block == nil {
return util.NULL, errors.New("pem.Decode:rsaPrivateKey decode error")
}
Expand Down
6 changes: 3 additions & 3 deletions wechat/v3/smart_guide_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// 服务人员注册API
// 注意:入参加密字段数据加密:wechat.V3EncryptText()
// 注意:入参加密字段数据加密:client.V3EncryptText()
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_1.shtml
func (c *ClientV3) V3SmartGuideReg(bm gopay.BodyMap) (wxRsp *SmartGuideRegRsp, err error) {
Expand Down Expand Up @@ -59,7 +59,7 @@ func (c *ClientV3) V3SmartGuideAssign(guideId, tradeNo string) (wxRsp *EmptyRsp,
}

// 服务人员查询API
// 注意:入参加密字段数据加密:wechat.V3EncryptText(),返回参数加密字段解密:wechat.V3DecryptText()
// 注意:入参加密字段数据加密:client.V3EncryptText(),返回参数加密字段解密:client.V3DecryptText()
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_3.shtml
func (c *ClientV3) V3SmartGuideQuery(bm gopay.BodyMap) (wxRsp *SmartGuideQueryRsp, err error) {
Expand Down Expand Up @@ -89,7 +89,7 @@ func (c *ClientV3) V3SmartGuideQuery(bm gopay.BodyMap) (wxRsp *SmartGuideQueryRs
}

// 服务人员信息更新API
// 注意:入参加密字段数据加密:wechat.V3EncryptText()
// 注意:入参加密字段数据加密:client.V3EncryptText()
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_4.shtml
func (c *ClientV3) V3SmartGuideUpdate(bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
Expand Down

0 comments on commit 5363939

Please sign in to comment.