-
Notifications
You must be signed in to change notification settings - Fork 24
Open
Description
写了一个demo, 用于校验payjs响应的签名, 适用于各种复杂的数据类型, 你看着改
package main
import (
"crypto/md5"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
)
var jsonStr = `
{
"name":"Markity",
"age":16,
"child":null,
"interests":["python","golang"],
"friends":[
{"name":"Jack","age":17,"interests":["lua"]},
{"name":"Mary","age":15,"interests":["java"]}
],
"compary":
{
"name":"Microsoft",
"workders":[
{"name":"Peter","age":22},
{"name":"Eric","age":23}
]
},
"sign":"XXX"
}
`
var mchKey = "xxxxx"
func main() {
start := time.Now()
fmt.Println(toolCheckSignResp([]byte(jsonStr), mchKey))
fmt.Println(time.Since(start))
}
// toolCheckSignResp 校验响应签名
func toolCheckSignResp(respData []byte, mchKey string) bool {
kvMap := make(map[string]interface{})
// 因为调用此方法前, 已经将respData Unmarshal为resp结构体, 证明json数据没有错误, 忽略error
json.Unmarshal(respData, &kvMap)
// 获取json数据里的签名
originSign, ok := kvMap["sign"]
// 对于某些特殊情况, 如重复退款, 即使return_code为1也无sign
// 所以如果respData中无sign字段, 则返回true
if !ok {
return true
}
// 获取keys并排序
delete(kvMap, "sign")
keys := make([]string, 0)
for k, _ := range kvMap {
keys = append(keys, k)
}
sort.Strings(keys)
// 将key=val追加入kvList中
kvList := make([]string, 0)
var walkMap func(string, interface{}, interface{}) = nil
walkMap = func(perfix string, obj interface{}, ks interface{}) {
// obj为[]interface{}或者map[string]interface{}类型, ks为[]string或者[]int类型
switch keys := ks.(type) {
case []string:
// 当ks为[]string类型时, obj为map[string]interface{}类型
object := obj.(map[string]interface{})
for _, key := range keys {
v := object[key]
// 根据签名算法, 值为null的不计入
if v == nil {
continue
}
// 若v为复合类型, 进入继续遍历
switch value := v.(type) {
case []interface{}:
_perfix := ""
if perfix == "" {
_perfix = key
} else {
_perfix = fmt.Sprintf("%v[%v]", perfix, key)
}
_keys := make([]int, 0, len(value))
for i := 0; i < len(value); i++ {
_keys = append(_keys, i)
}
walkMap(_perfix, value, _keys)
continue
case map[string]interface{}:
_perfix := ""
if perfix == "" {
_perfix = key
} else {
_perfix = fmt.Sprintf("%v[%v]", perfix, key)
}
_keys := make([]string, 0)
for k, _ := range value {
_keys = append(_keys, k)
}
sort.Strings(_keys)
walkMap(_perfix, value, _keys)
continue
}
// 为基础类型
if perfix == "" {
kvList = append(kvList, fmt.Sprintf("%v=%v", key, v))
} else {
kvList = append(kvList, fmt.Sprintf("%v[%v]=%v", perfix, key, v))
}
}
case []int:
// keys为[]int类型, perfix不可能为""
// 当ks为[]int, obj为[]interface{}
object := obj.([]interface{})
for _, key := range keys {
v := object[key]
if v == nil {
continue
}
switch value := v.(type) {
// 若v为复合类型, 进入继续遍历
case []interface{}:
_perfix := fmt.Sprintf("%v[%v]", perfix, key)
_keys := make([]int, 0, len(value))
for i := 0; i < len(value); i++ {
_keys = append(_keys, i)
}
walkMap(_perfix, value, _keys)
continue
case map[string]interface{}:
_perfix := fmt.Sprintf("%v[%v]", perfix, key)
_keys := make([]string, 0)
for k, _ := range value {
_keys = append(_keys, k)
}
sort.Strings(_keys)
walkMap(_perfix, value, _keys)
continue
}
// 为基础类型
kvList = append(kvList, fmt.Sprintf("%v[%v]=%v", perfix, key, v))
}
}
}
walkMap("", kvMap, keys)
kvList = append(kvList, fmt.Sprintf("key=%v", mchKey))
kvChain := strings.Join(kvList, "&")
fmt.Println(kvChain)
// 比较签名
realSign := strings.ToUpper(fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(kvList, "&")))))
if originSign != realSign {
return false
}
return true
}
/*输出
age=16&compary[name]=Microsoft&compary[workders][0][age]=22&compary[workders][0][name]=Peter&compary[workders][1][age]=23&compary[workders][1][name]=Eric&friends[0][age]=17&friends[0][interests][0]=lua&friends[0][name]=Jack&friends[1][age]=15&friends[1][interests][0]=java&friends[1][name]=Mary&interests[0]=python&interests[1]=golang&name=Markity&key=xxxxx
false
132.6µs
*/Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels