/
notify_result.go
100 lines (87 loc) · 3.08 KB
/
notify_result.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package pay
import (
"fmt"
"github.com/fatih/structs"
"github.com/silenceper/wechat/util"
"github.com/spf13/cast"
"reflect"
"sort"
"strings"
)
// doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
// NotifyResult 下单回调
type NotifyResult struct {
ReturnCode *string `xml:"return_code"`
ReturnMsg *string `xml:"return_msg"`
AppID *string `xml:"appid" json:"appid"`
MchID *string `xml:"mch_id"`
DeviceInfo *string `xml:"device_info"`
NonceStr *string `xml:"nonce_str"`
Sign *string `xml:"sign"`
SignType *string `xml:"sign_type"`
ResultCode *string `xml:"result_code"`
ErrCode *string `xml:"err_code"`
ErrCodeDes *string `xml:"err_code_des"`
OpenID *string `xml:"openid"`
IsSubscribe *string `xml:"is_subscribe"`
TradeType *string `xml:"trade_type"`
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 消息通知返回
type NotifyResp struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
}
// VerifySign 验签
func (pcf *Pay) VerifySign(notifyRes NotifyResult) bool {
// STEP1, 转换 struct 为 map,并对 map keys 做排序
resMap := structs.Map(notifyRes)
sortedKeys := make([]string, 0, len(resMap))
for k := range resMap {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
// STEP2, 对key=value的键值对用&连接起来,略过空值 & sign
var signStrings string
for _, k := range sortedKeys {
value := fmt.Sprintf("%v", cast.ToString(resMap[k]))
if value != "" && strings.ToLower(k) != "sign" {
signStrings = signStrings + getTagKeyName(k, ¬ifyRes) + "=" + value + "&"
}
}
// STEP3, 在键值对的最后加上key=API_KEY
signStrings = signStrings + "key=" + pcf.PayKey
// STEP4, 进行MD5签名并且将所有字符转为大写.
sign := util.MD5Sum(signStrings)
if sign != *notifyRes.Sign {
return false
}
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
}