9 Commits

Author SHA1 Message Date
  lijianbin e845674f4b update 2 years ago
  lijianbin c0ce0771ac 增加site_id参数 2 years ago
  guzeng 560548b22c 微信支付退款client 3 years ago
  guzeng 10f3760acb 增加data处理方法 3 years ago
  guzeng 7aadadbae3 增加支付退款 3 years ago
  listen bd48d1cc30 加入图片和文字检测 3 years ago
  guzeng f94ec81d83 更新pb.go 3 years ago
  listen 131fea8347 加入检测方法 3 years ago
  listen 30e4e1d689 更改小程序码参数 3 years ago
12 changed files with 413 additions and 16 deletions
Split View
  1. +1
    -1
      common.go
  2. +106
    -0
      data.go
  3. +3
    -2
      go.mod
  4. +8
    -6
      go.sum
  5. +5
    -5
      miniapp_qrcode.client.go
  6. +8
    -2
      miniapp_qrcode.client_test.go
  7. +63
    -0
      pay.client.go
  8. +76
    -0
      pay.client_test.go
  9. +97
    -0
      security_check.go
  10. +31
    -0
      security_check_test.go
  11. +12
    -0
      weixin.pb.go
  12. +3
    -0
      weixin.proto

+ 1
- 1
common.go View File

@ -1,7 +1,7 @@
package weixinrpc
import (
"git.tetele.net/tgo/conf"
"git.tetele.net/yueheng/conf"
)
const DES_KEY = "wxserrpc"


+ 106
- 0
data.go View File

@ -0,0 +1,106 @@
package weixinrpc
import (
"encoding/json"
"errors"
"strconv"
"time"
"git.tetele.net/tgo/crypter"
"github.com/golang/protobuf/proto"
)
func SetResData(data interface{}, res *Response) {
res_data_json, err := json.Marshal(data)
if err == nil {
encryData := crypter.DesEn(string(res_data_json), DES_KEY)
now_str := strconv.FormatInt(time.Now().Unix(), 10)
res_sign := Sign(encryData, now_str)
res.Data = proto.String(encryData)
res.Time = proto.String(now_str)
res.Sign = proto.String(res_sign)
}
}
func SetReqData(arg interface{}) (*Request, error) {
data_json, err := json.Marshal(arg)
if err != nil {
return nil, err
}
now_int64 := time.Now().Unix()
encryData := crypter.DesEn(string(data_json), DES_KEY)
now := strconv.FormatInt(now_int64, 10)
sign := Sign(encryData, now)
return &Request{proto.String(encryData), proto.String(now), proto.String(sign), nil}, nil
}
func GetReqData(req *Request) (string, error) {
res_data := req.GetData()
if res_data != "" {
time_int64, err := strconv.ParseInt(req.GetTime(), 10, 64)
if err != nil {
return "", err
}
now_int64 := time.Now().Unix()
if now_int64-time_int64 > 10 || time_int64-now_int64 > 10 {
//时间误差前后10秒,返回
return "", errors.New("返回时间错误")
}
check_sign := CheckSign(req.GetSign(), res_data, req.GetTime())
if !check_sign {
return "", errors.New("返回数据签名错误")
}
//解密
return crypter.DesDe(res_data, DES_KEY), nil
}
return "", nil
}
func GetResData(res *Response) (string, error) {
res_data := res.GetData()
if res_data != "" {
time_int64, err := strconv.ParseInt(res.GetTime(), 10, 64)
if err != nil {
return "", err
}
now_int64 := time.Now().Unix()
if now_int64-time_int64 > 10 || time_int64-now_int64 > 10 {
//时间误差前后10秒,返回
return "", errors.New("返回时间错误")
}
check_sign := CheckSign(res.GetSign(), res_data, res.GetTime())
if !check_sign {
return "", errors.New("返回数据签名错误")
}
//解密
return crypter.DesDe(res_data, DES_KEY), nil
}
return "", nil
}

+ 3
- 2
go.mod View File

@ -3,9 +3,10 @@ module git.tetele.net/tgo/weixinrpc
go 1.14
require (
git.tetele.net/tgo/conf v0.39.3
git.tetele.net/tgo/crypter v0.2.2
github.com/chai2010/protorpc v1.0.0
git.tetele.net/tgo/helper v0.2.6
git.tetele.net/yueheng/conf v1.2.4
github.com/chai2010/protorpc v1.1.3
github.com/golang/protobuf v1.0.0
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect


+ 8
- 6
go.sum View File

@ -1,13 +1,15 @@
git.tetele.net/tgo/conf v0.39.3 h1:yjeJKmOHMJUeRl5Q3FVCLjIdIcor7UkohycyM87cGng=
git.tetele.net/tgo/conf v0.39.3/go.mod h1:AWVIBEDE5dtotthUgR0SWaR2Qa6/f+O5WQ3s7Tj8q7A=
git.tetele.net/tgo/crypter v0.2.2 h1:YMQJh2Gj5Po4ZfelJUmXBKi01UbmtiSy3bmqRfnYQMo=
git.tetele.net/tgo/crypter v0.2.2/go.mod h1:vfvRLZA8+lHNgNXneOcgvVhDyuv25ZRb+C6xHOmXNx0=
github.com/chai2010/protorpc v1.0.0 h1:aJ45G9sl1utSKo35EqnBSTs5jqTpdJDJAuZMMYPAtFo=
github.com/chai2010/protorpc v1.0.0/go.mod h1:woR3WwjaQDqFjlzdVsFEKiK5Ur12QL8mYxVPjfr5z54=
git.tetele.net/tgo/helper v0.2.6 h1:JC+N+If/bGvcwuUSklva17YDNtKBV2Qpvl5RQpMySOY=
git.tetele.net/tgo/helper v0.2.6/go.mod h1:89mQwyfqZ+t8YXiVwzSxA70gLlUNqoZGDEUxvV46jXk=
git.tetele.net/yueheng/conf v1.2.4 h1:QQr6yflZa9PjISTyNDBL25qOmkRYR06BCJJWWagETQI=
git.tetele.net/yueheng/conf v1.2.4/go.mod h1:qRujMTqjMByvdC05qdfscZMFRKM5XA1qbtz4rnFyStY=
github.com/chai2010/protorpc v1.1.3 h1:VJK5hIoZn0XCGol0GmbxZkUG6FbTI5LP2Lam6RVd15w=
github.com/chai2010/protorpc v1.1.3/go.mod h1:/wO0kiyVdu7ug8dCMrA2yDr2vLfyhsLEuzLa9J2HJ+I=
github.com/golang/protobuf v1.0.0 h1:lsek0oXi8iFE9L+EXARyHIjU5rlWIhhTkjDz3vHhWWQ=
github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=


+ 5
- 5
miniapp_qrcode.client.go View File

@ -10,7 +10,7 @@ import (
"github.com/golang/protobuf/proto"
)
func GetMiniAppQrcode(appId, appSecret, page,scene string, url ...string) (string, error) {
func GetMiniAppQrcode(siteId, appId, appSecret string, qrcodeParams map[string]interface{}, url ...string) (string, error) {
conn, err := rpc_server_conn(url...)
if err != nil {
@ -18,11 +18,11 @@ func GetMiniAppQrcode(appId, appSecret, page,scene string, url ...string) (strin
}
defer conn.Close()
data := map[string]string{}
data := map[string]interface{}{}
data["site_id"] = siteId
data["app_id"] = appId
data["app_secret"] = appSecret
data["page"] = page
data["scene"] = scene
data["qrcode"] = qrcodeParams
data_json, err := json.Marshal(data)
if err != nil {
@ -51,7 +51,7 @@ func GetMiniAppQrcode(appId, appSecret, page,scene string, url ...string) (strin
return "", err
}
//解密
// 解密
res_data_de, err := GetOrgData(res)
if err != nil {


+ 8
- 2
miniapp_qrcode.client_test.go View File

@ -5,11 +5,17 @@ import (
)
func Test_GetMiniappCode(t *testing.T){
site_id := "1198881"
appid := "wx3d53ccbaf69f7995"
appSecret := "165983626235636be54a16404e3e70a7"
page := ""
scene := "user_id=2"
qrcode,err := GetMiniAppQrcode(appid,appSecret,page,scene)
scene := "user_id=19"
qrcodeParams := map[string]interface{}{
"page":page,
"scene":scene,
// "is_hyaline":true,
}
qrcode,err := GetMiniAppQrcode(site_id,appid,appSecret,qrcodeParams)
t.Log(qrcode)
t.Log(err)


+ 63
- 0
pay.client.go View File

@ -0,0 +1,63 @@
package weixinrpc
import (
"encoding/json"
)
/**
* 订单号,子单号,总金额,退款金额,微信商户id,微信商户平台API私钥,平台证书,商户平台证书序列号,商品名,退款原因商品id,回调地址
*/
func PayRefund(order_sn, sn, total, refund, wx_mp_mch_id, wx_mch_apiclient_key,
wx_pay_cert, mch_serial_no, title, uuid, reason, notify_url string,
url ...string) (map[string]string, error) {
conn, err := rpc_server_conn(url...)
if err != nil {
return nil, err
}
defer conn.Close()
data := map[string]string{
"order_sn": order_sn,
"sn": sn,
"total": total,
"refund": refund,
"wx_mp_mch_id": wx_mp_mch_id,
"wx_mch_apiclient_key": wx_mch_apiclient_key,
"wx_pay_cert": wx_pay_cert,
"mch_serial_no": mch_serial_no,
"reason": reason,
"uuid": uuid,
"title": title,
"notify_url": notify_url,
}
req, err := SetReqData(data)
if err != nil {
return nil, err
}
res := &Response{}
err = conn.PayRefund(req, res)
if err != nil {
return nil, err
}
res_data_de, err := GetResData(res)
if err != nil {
return nil, err
}
if res_data_de == "" {
return nil, nil
}
var res_arr map[string]string
err = json.Unmarshal([]byte(res_data_de), &res_arr)
if err != nil {
return nil, err
}
return res_arr, nil
}

+ 76
- 0
pay.client_test.go View File

@ -0,0 +1,76 @@
package weixinrpc
import (
"testing"
)
func Test_PayRefund(t *testing.T) {
order_sn := "1638614195578314926" //订单号
sn := "1638614195546464238" //子单号
total := "0.04" //总金额
refund := "0.04" //退款金额
wx_mp_mch_id := "1612824503" //微信商户id
wx_mch_apiclient_key := `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDS6pGtfloagNoX
NPc27PFaw+K/H4n8Z7sdHyXSD6hlLzvTq7Fx4/MZYgmmXrhAjtdW/+KeKrHnYyAq
jNlkIamCVhteNZd9XQ3SCWpmqLVtT6sMV5Xtx31A8WqRi0ABReiNlTjnlqOntpkr
bP/9NTwQJLsAVKCbkOtaL3fFm5aTd6Jsu4BTq/4GWQOhY4UfsBcwBRTOJ9LsowX3
CZA4npha8nVftKT/ut7eqKgD11l6VrCgsksJ+swEmz4Je7WhEplDp+4nNdpEXwE0
u5/CWqu/kZCf2LFHmikHMstVy/FMZ66l5sHXpEA8e5dfr92/mfK7R2nvER/M6VPg
vkFWmL19AgMBAAECggEAOAH4G0URMjaDM2RqPVigIsUfojcC0lbNVkdeKLDlu7DW
Rzgxj5fDhzsEavx+Gw6TWlPq3qthwJsPAJ2UYMWbmLO64sKCbtTWBa9gZNBqFRPx
zP45HwI5XZR+AxYiMfRZc7dre/wBi1iuxdxVAe0v/O10BvtyBr1t8e3m9T+Ctbe0
m6DLABIkrnwULBuHuWr1aFq2anmDrEiVzE09792qSPOspP/gbBnhkispu3DyqcaK
0lI8s/asGfa0OI7XPVR0L+9pXmbPIE75JcHp2YOxXIL/PWcGxy6G6M7Riw4CSb4N
zHrK1hoz8bynGrRGM5UzUfKgcZHYpLfEV5mOuybvYQKBgQDwdMqyhDvIx61Xw+cg
HfCuk6pddZoIlq4cdA8by2WWtM2+KVO5RIOnRWkMrVHQ02piYyzXLEbFk+jWi0U9
3f6Ph0aiX9Zg5tr8/EMArYySOyL6CNFxPe1rkK3edcbwZRphJ2RZi0nIhAzbwqKU
MOYqdM2KgAHSkofCA4nFYFc9NQKBgQDgjO70uHWB3Er8orkxo9BIoFqOyZKZMTjE
yDuhu3EyY6O+TrdWJQGeTcoeXeGh2sIqxri7T2CeLip669TiSkTHm7M6EhF5LB4g
qMCl2zjDtdLAxc1zlDXHMjWh9VdQ9adsb7eQqhIm7vRCQ7oABhGiXXvDvxugJ8RN
mpHYK04wKQKBgAld81t67T1IEgeeOQ22PN8AH53ea+6zt/qhxsjlZoK1bmJfB8Tq
11oXyRzWT56b7cQBawjCz8r4lRRufncHg9ghg+3lX9uMgrFiPlXzbMtxhE5LM6V+
rRYIn81Ptz08Iwfv2efnFiu6gSm6bkzpjr3OqQchL3D9hk5XhvFqbFuVAoGBAIKX
M/k6tYwac7nNYOrPnDhAmank7M8O4zb+RD/g5QorDHWHDfSZfQF1uBBFBQ2+TaHX
BGRa25PiwW3PbXVVP/7ePDOPgn33/GV9/tv2TGL1gWX/I2cOUOBSAQL5zhgVZZMY
vabyYbAm1AMdpDSTUvocZ/gFUqmntvBy7lLLjKNRAoGAaj3O6BP/djkE9zsm7Ao0
tqgwec15iaGz/5rRYXyVrWo0UqF0lNvXK2m5D0EiQeGSv3LR9EuilysVego4MvQk
Dn8ITNRti+YCeRgPBGd38+o4wWXsS50WtlQMWx2DmYrORPYadHEuA9lo1rt5uDoR
IOLIPinMkOLYWAdLHqPzL7E=
-----END PRIVATE KEY-----` //微信商户平台API私钥
wx_pay_cert := `-----BEGIN CERTIFICATE-----
MIID3DCCAsSgAwIBAgIUSdPFwujSihpwlK7m057+WdAXRnAwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjEwODExMDcwMzExWhcNMjYwODEwMDcwMzExWjBuMRgwFgYDVQQDDA9U
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSzutwzsCf03UmqtP5
z+oMAyoPK78uNH9+inpMZlkLJslruerVhRVgz+U/Yz7t25GXha4Ui0EQ/HoaIUea
wbOghYA7GAk21lOU0WLaX8a9U2t96nme9PJ5yqnqi8P7FpX+HsJG+3WRhL0D3hm4
iLBEhMbHXvzri2NIbYDiac62Ekx6xtk3XjmfyTgabYRzTIJ8cw8RWW2+X0GYlyi9
biXy9diVd/rohl5++6ATcRmk51skJaPI4qaQDBjpedaS/pSd83ujhs51M/CvqgQ6
Woczk/ha5w9PVFJTIwIMzmr3HSXjYtKxgMucrfpNOlrb2uVD4xmulDA6XAhk9Hx/
bj8fAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc
MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js
P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ
KoZIhvcNAQELBQADggEBAA69QPm7w9LcXU5lmyQ0HQdQFp9Rdq3IYmpEPDytRL0M
L40PKRc4VdS9ttZN4PUxh0Gat4EoYD7YR3nfB7Lx1xu00G3Rondx7g7ryTVN3y5E
SioX94JsZ8QD3NDHuCPwgMT5SS1FIyO9ls8x82vtagZc1M9YjP1x8kfledJxC4NI
JhpX1cuKgCbRLhi0qrerRoQlbbb7oP6NsBnXuVCPCHzxDg+YgLuPrz82w7Z5+UxZ
G0KYKvGdupW5Sc8n+yJczCsmhhhmJy8N17qf60UGi9vQdHXVy2nwHRMTnjTpP56x
52hbci3SxbjNY9IC+J+jaYDM6ChMPVIsdEniJKpof5E=
-----END CERTIFICATE-----` //平台证书
mch_serial_no := "735B1DE549DB6BF12796BA0EF87BABA7D3853080" //商户平台证书序列号
reason := "缺货取消" //退款原因
uuid := "28303" //退款原因
title := "抽巾纹~~" //回调地址
notify_url := "https://manager.youpincat.com/api/wxrefunds/refund_notify" //回调地址
ret, err := PayRefund(order_sn, sn, total, refund, wx_mp_mch_id, wx_mch_apiclient_key,
wx_pay_cert, mch_serial_no, title, uuid, reason, notify_url)
t.Log(ret)
t.Log(err)
}

+ 97
- 0
security_check.go View File

@ -0,0 +1,97 @@
package weixinrpc
import (
"encoding/json"
"git.tetele.net/tgo/crypter"
"github.com/golang/protobuf/proto"
"strconv"
"time"
)
//检测图片是否合法
func ImgSecCheck(appId, appSecret,imgUrl string, url ...string) (error) {
conn, err := rpc_server_conn(url...)
if err != nil {
return err
}
defer conn.Close()
data := map[string]interface{}{}
data["app_id"] = appId
data["app_secret"] = appSecret
data["img_url"] = imgUrl
data_json, err := json.Marshal(data)
if err != nil {
return err
}
encryData := crypter.DesEn(string(data_json), DES_KEY)
now_int64 := time.Now().Unix()
now := strconv.FormatInt(now_int64, 10)
sign := Sign(encryData, now)
req := &Request{
proto.String(encryData),
proto.String(now),
proto.String(sign),
nil}
res := &Response{}
err = conn.ImgSecCheck(req, res)
if err != nil {
return err
}
return nil
}
//检测文本是否合法
func MsgSecCheck(appId, appSecret string,checkData map[string]interface{}, url ...string)error{
conn, err := rpc_server_conn(url...)
if err != nil {
return err
}
defer conn.Close()
data := map[string]interface{}{}
data["app_id"] = appId
data["app_secret"] = appSecret
data["check_data"] = checkData
data_json, err := json.Marshal(data)
if err != nil {
return err
}
encryData := crypter.DesEn(string(data_json), DES_KEY)
now_int64 := time.Now().Unix()
now := strconv.FormatInt(now_int64, 10)
sign := Sign(encryData, now)
req := &Request{
proto.String(encryData),
proto.String(now),
proto.String(sign),
nil}
res := &Response{}
err = conn.MsgSecCheck(req, res)
if err != nil {
return err
}
return nil
}

+ 31
- 0
security_check_test.go View File

@ -0,0 +1,31 @@
package weixinrpc
import (
"git.tetele.net/tgo/helper"
"testing"
)
func Test_CheckImg(t *testing.T){
appid := "wx3d53ccbaf69f7995"
appSecret := "165983626235636be54a16404e3e70a7"
imgUrl := helper.TencentCloudImageCompress("https://images-1306193253.cos.ap-guangzhou.myqcloud.com/uploads/20211026/1635213788c5713f49816c74a0e130694ed6544e71.jpg","450")
//imgUrl := "https://images-1306193253.cos.ap-guangzhou.myqcloud.com/uploads/20211026/1635213788c5713f49816c74a0e130694ed6544e71.jpg"
err := ImgSecCheck(appid,appSecret,imgUrl)
t.Log(err)
}
func Test_CheckMsg(t *testing.T){
appid := "wx3d53ccbaf69f7995"
appSecret := "165983626235636be54a16404e3e70a7"
checkData := map[string]interface{}{
"openid":"oLBHE4kRuj8ywGKuXMgLbmFKrdkM",
"scene":3,
"content":"",
}
err := MsgSecCheck(appid,appSecret,checkData)
t.Log(err)
}

+ 12
- 0
weixin.pb.go View File

@ -106,6 +106,9 @@ type WeixinRpcService interface {
GetAppOpenid(in *Request, out *Response) error
GetMpUserInfo(in *Request, out *Response) error
GetMiniappQrcode(in *Request, out *Response) error
ImgSecCheck(in *Request, out *Response) error
MsgSecCheck(in *Request, out *Response) error
PayRefund(in *Request, out *Response) error
}
// AcceptWeixinRpcServiceClient accepts connections on the listener and serves requests
@ -201,6 +204,15 @@ func (c *WeixinRpcServiceClient) GetMpUserInfo(in *Request, out *Response) error
func (c *WeixinRpcServiceClient) GetMiniappQrcode(in *Request, out *Response) error {
return c.Call("WeixinRpcService.GetMiniappQrcode", in, out)
}
func (c *WeixinRpcServiceClient) ImgSecCheck(in *Request, out *Response) error {
return c.Call("WeixinRpcService.ImgSecCheck", in, out)
}
func (c *WeixinRpcServiceClient) MsgSecCheck(in *Request, out *Response) error {
return c.Call("WeixinRpcService.MsgSecCheck", in, out)
}
func (c *WeixinRpcServiceClient) PayRefund(in *Request, out *Response) error {
return c.Call("WeixinRpcService.PayRefund", in, out)
}
// DialWeixinRpcService connects to an WeixinRpcService at the specified network address.
func DialWeixinRpcService(network, addr string) (*WeixinRpcServiceClient, *rpc.Client, error) {


+ 3
- 0
weixin.proto View File

@ -26,4 +26,7 @@ service WeixinRpcService {
rpc getAppOpenid(Request) returns (Response); // app的openid
rpc getMpUserInfo(Request) returns (Response); //
rpc getMiniappQrcode(Request) returns (Response); //
rpc imgSecCheck(Request) returns (Response); //
rpc msgSecCheck(Request) returns (Response); //
rpc payRefund(Request) returns (Response); //v3支付退款
}

Loading…
Cancel
Save