mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-13 01:02:27 +08:00
重写 pay/NotifyResult VerifySign
This commit is contained in:
2
go.mod
2
go.mod
@@ -5,12 +5,14 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
github.com/astaxie/beego v1.7.1
|
github.com/astaxie/beego v1.7.1
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a
|
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a
|
||||||
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/gin-gonic/gin v1.1.4
|
github.com/gin-gonic/gin v1.1.4
|
||||||
github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b // indirect
|
github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b // indirect
|
||||||
github.com/gomodule/redigo v2.0.1-0.20180627144507-2cd21d9966bf+incompatible
|
github.com/gomodule/redigo v2.0.1-0.20180627144507-2cd21d9966bf+incompatible
|
||||||
github.com/kr/pretty v0.1.0
|
github.com/kr/pretty v0.1.0
|
||||||
github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739 // indirect
|
github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c // indirect
|
github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c // indirect
|
||||||
|
github.com/spf13/cast v1.3.1
|
||||||
github.com/stretchr/testify v1.4.0 // indirect
|
github.com/stretchr/testify v1.4.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
|
||||||
golang.org/x/net v0.0.0-20191125084936-ffdde1057850 // indirect
|
golang.org/x/net v0.0.0-20191125084936-ffdde1057850 // indirect
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -4,6 +4,9 @@ github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a h1:k5TuEkqEYCR
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
github.com/gin-gonic/gin v1.1.4 h1:XLaCFbU39SSGRQrEeP7Z7mM3lvRqC4vE5tEaVdLDdSE=
|
github.com/gin-gonic/gin v1.1.4 h1:XLaCFbU39SSGRQrEeP7Z7mM3lvRqC4vE5tEaVdLDdSE=
|
||||||
github.com/gin-gonic/gin v1.1.4/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
github.com/gin-gonic/gin v1.1.4/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||||
github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b h1:fE/yi9pibxGEc0gSJuEShcsBXE2d5FW3OudsjE9tKzQ=
|
github.com/golang/protobuf v0.0.0-20161117033126-8ee79997227b h1:fE/yi9pibxGEc0gSJuEShcsBXE2d5FW3OudsjE9tKzQ=
|
||||||
@@ -21,7 +24,10 @@ github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c h1:YHHK/dEmr2Jo1cW
|
|||||||
github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.0-20161123143637-30a891c33c7c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
|
|||||||
@@ -2,36 +2,57 @@ package pay
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/fatih/structs"
|
||||||
"github.com/silenceper/wechat/util"
|
"github.com/silenceper/wechat/util"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base 公用参数
|
// doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
|
||||||
type Base struct {
|
|
||||||
AppID string `xml:"appid"`
|
|
||||||
MchID string `xml:"mch_id"`
|
|
||||||
NonceStr string `xml:"nonce_str"`
|
|
||||||
Sign string `xml:"sign"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyResult 下单回调
|
// NotifyResult 下单回调
|
||||||
type NotifyResult struct {
|
type NotifyResult struct {
|
||||||
Base
|
ReturnCode *string `xml:"return_code"`
|
||||||
ReturnCode string `xml:"return_code"`
|
ReturnMsg *string `xml:"return_msg"`
|
||||||
ReturnMsg string `xml:"return_msg"`
|
|
||||||
ResultCode string `xml:"result_code"`
|
AppID *string `xml:"appid" json:"appid"`
|
||||||
OpenID string `xml:"openid"`
|
MchID *string `xml:"mch_id"`
|
||||||
IsSubscribe string `xml:"is_subscribe"`
|
DeviceInfo *string `xml:"device_info"`
|
||||||
TradeType string `xml:"trade_type"`
|
NonceStr *string `xml:"nonce_str"`
|
||||||
BankType string `xml:"bank_type"`
|
Sign *string `xml:"sign"`
|
||||||
TotalFee int `xml:"total_fee"`
|
SignType *string `xml:"sign_type"`
|
||||||
FeeType string `xml:"fee_type"`
|
ResultCode *string `xml:"result_code"`
|
||||||
CashFee int `xml:"cash_fee"`
|
ErrCode *string `xml:"err_code"`
|
||||||
CashFeeType string `xml:"cash_fee_type"`
|
ErrCodeDes *string `xml:"err_code_des"`
|
||||||
TransactionID string `xml:"transaction_id"`
|
OpenID *string `xml:"openid"`
|
||||||
OutTradeNo string `xml:"out_trade_no"`
|
IsSubscribe *string `xml:"is_subscribe"`
|
||||||
Attach string `xml:"attach"`
|
TradeType *string `xml:"trade_type"`
|
||||||
TimeEnd string `xml:"time_end"`
|
BankType *string `xml:"bank_type"`
|
||||||
|
TotalFee *int `xml:"total_fee"`
|
||||||
|
SettlementTotalFee *int `xml:"settlement_total_fee"`
|
||||||
|
FeeType *string `xml:"fee_type"`
|
||||||
|
CashFee *string `xml:"cash_fee"`
|
||||||
|
CashFeeType *string `xml:"cash_fee_type"`
|
||||||
|
CouponFee *int `xml:"coupon_fee"`
|
||||||
|
CouponCount *int `xml:"coupon_count"`
|
||||||
|
|
||||||
|
// coupon_type_$n 这里只声明 3 个,如果有更多的可以自己组合
|
||||||
|
CouponType0 *string `xml:"coupon_type_0"`
|
||||||
|
CouponType1 *string `xml:"coupon_type_1"`
|
||||||
|
CouponType2 *string `xml:"coupon_type_2"`
|
||||||
|
CouponID0 *string `xml:"coupon_id_0"`
|
||||||
|
CouponID1 *string `xml:"coupon_id_1"`
|
||||||
|
CouponID2 *string `xml:"coupon_id_2"`
|
||||||
|
CouponFeed0 *string `xml:"coupon_fee_0"`
|
||||||
|
CouponFeed1 *string `xml:"coupon_fee_1"`
|
||||||
|
CouponFeed2 *string `xml:"coupon_fee_2"`
|
||||||
|
|
||||||
|
TransactionID *string `xml:"transaction_id"`
|
||||||
|
OutTradeNo *string `xml:"out_trade_no"`
|
||||||
|
Attach *string `xml:"attach"`
|
||||||
|
TimeEnd *string `xml:"time_end"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyResp 消息通知返回
|
// NotifyResp 消息通知返回
|
||||||
@@ -42,46 +63,38 @@ type NotifyResp struct {
|
|||||||
|
|
||||||
// VerifySign 验签
|
// VerifySign 验签
|
||||||
func (pcf *Pay) VerifySign(notifyRes NotifyResult) bool {
|
func (pcf *Pay) VerifySign(notifyRes NotifyResult) bool {
|
||||||
// 封装map 请求过来的 map
|
// STEP1, 转换 struct 为 map,并对 map keys 做排序
|
||||||
resMap := make(map[string]interface{})
|
resMap := structs.Map(notifyRes)
|
||||||
// base
|
|
||||||
resMap["appid"] = notifyRes.AppID
|
|
||||||
resMap["mch_id"] = notifyRes.MchID
|
|
||||||
resMap["nonce_str"] = notifyRes.NonceStr
|
|
||||||
// NotifyResult
|
|
||||||
resMap["return_code"] = notifyRes.ReturnCode
|
|
||||||
resMap["result_code"] = notifyRes.ResultCode
|
|
||||||
resMap["openid"] = notifyRes.OpenID
|
|
||||||
resMap["is_subscribe"] = notifyRes.IsSubscribe
|
|
||||||
resMap["trade_type"] = notifyRes.TradeType
|
|
||||||
resMap["bank_type"] = notifyRes.BankType
|
|
||||||
resMap["total_fee"] = notifyRes.TotalFee
|
|
||||||
resMap["fee_type"] = notifyRes.FeeType
|
|
||||||
resMap["cash_fee"] = notifyRes.CashFee
|
|
||||||
resMap["transaction_id"] = notifyRes.TransactionID
|
|
||||||
resMap["out_trade_no"] = notifyRes.OutTradeNo
|
|
||||||
resMap["attach"] = notifyRes.Attach
|
|
||||||
resMap["time_end"] = notifyRes.TimeEnd
|
|
||||||
// 支付key
|
|
||||||
sortedKeys := make([]string, 0, len(resMap))
|
sortedKeys := make([]string, 0, len(resMap))
|
||||||
for k := range resMap {
|
for k := range resMap {
|
||||||
sortedKeys = append(sortedKeys, k)
|
sortedKeys = append(sortedKeys, k)
|
||||||
}
|
}
|
||||||
sort.Strings(sortedKeys)
|
sort.Strings(sortedKeys)
|
||||||
// STEP2, 对key=value的键值对用&连接起来,略过空值
|
|
||||||
|
// STEP2, 对key=value的键值对用&连接起来,略过空值 & sign
|
||||||
var signStrings string
|
var signStrings string
|
||||||
for _, k := range sortedKeys {
|
for _, k := range sortedKeys {
|
||||||
value := fmt.Sprintf("%v", resMap[k])
|
value := fmt.Sprintf("%v", cast.ToString(resMap[k]))
|
||||||
if value != "" {
|
if value != "" && strings.ToLower(k) != "sign" {
|
||||||
signStrings = signStrings + k + "=" + value + "&"
|
signStrings = signStrings + getTagKeyName(k, ¬ifyRes) + "=" + value + "&"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP3, 在键值对的最后加上key=API_KEY
|
// STEP3, 在键值对的最后加上key=API_KEY
|
||||||
signStrings = signStrings + "key=" + pcf.PayKey
|
signStrings = signStrings + "key=" + pcf.PayKey
|
||||||
|
|
||||||
// STEP4, 进行MD5签名并且将所有字符转为大写.
|
// STEP4, 进行MD5签名并且将所有字符转为大写.
|
||||||
sign := util.MD5Sum(signStrings)
|
sign := util.MD5Sum(signStrings)
|
||||||
if sign != notifyRes.Sign {
|
if sign != *notifyRes.Sign {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTagKeyName(key string, notifyRes *NotifyResult) string {
|
||||||
|
s := reflect.TypeOf(notifyRes).Elem()
|
||||||
|
f, _ := s.FieldByName(key)
|
||||||
|
name := f.Tag.Get("xml")
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user