源码如下
package main
import (
"fmt"
"sort"
"encoding/json"
"crypto/md5"
"encoding/hex"
"bytes"
)
func main() {
params := make(map[string]string)
params["name"] = "111"
params["domain"] = "www.baidu.com?name=1&id=1"
// 排序
keys := make([]string, len(params))
i := 0
for k, _ := range params {
keys[i] = k
i++
}
sort.Strings(keys)
for _, k := range keys {
fmt.Println(k)
}
byteBuf := bytes.NewBuffer([]byte{})
encoder := json.NewEncoder(byteBuf)
// 特殊字符不转义
encoder.SetEscapeHTML(false)
err := encoder.Encode(params)
if err != nil {
panic(err)
}
data := byteBuf.String()
fmt.Println(data)
h := md5.New()
// 与 php 一致
h.Write([]byte(`{"domain":"www.baidu.com?name=1&id=1","name":"111"}`))
// 不一致
// h.Write([]byte(data))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
// php 结果为 06820973e7b8d3acdb4763264a803620
}
1
also24 2020-06-14 13:27:38 +08:00 via Android
说个题外话:
也不知道谁带起的这种风气,用这种方式来进行检验。 JSON 序列化的时候,是否换行,是否缩进,是否转义都会造成序列化结果字符串的差异。 正确的做法是直接传输序列化后的 JSON String,计算 hash 的时候也直接针对整个 JSON String |
3
marquina 2020-06-14 13:34:09 +08:00
json 在我这个 pythoner 眼里就是一个 dict,我也从来不会对 json 序列化、反序列化时 key 的顺序有任何期待,更别提算 md5 这种操作了
|
5
haiyang416 2020-06-14 13:51:19 +08:00
|
6
chinvo 2020-06-14 13:55:10 +08:00 via iPhone
签名的正确玩法是对 http body 签名,签名结果放到 header 里
这样就不涉及排序问题 |
7
Nick66 OP @haiyang416 感谢,解决了。
|
8
Vegetable 2020-06-14 14:02:36 +08:00
byteBuf.Bytes()
[123 34 100 111 109 97 105 110 34 58 34 119 119 119 46 98 97 105 100 117 46 99 111 109 63 110 97 109 101 61 49 38 105 100 61 49 34 44 34 110 97 109 101 34 58 34 49 49 49 34 125 10] 最后多了一个 0010,换行符。trim 掉就一样了 h.Write(bytes.TrimSpace(byteBuf.Bytes())) fmt.Println(hex.EncodeToString(h.Sum(nil))) 06820973e7b8d3acdb4763264a803620 |
10
also24 2020-06-14 18:21:17 +08:00
@janxin #9
那也可以通过对整个 http body 进行 hash,签名放进 header 的方式来处理。 或者将原有 body 整个包装进一个 JSON String 字段来解决,都可以避免字段乱序或序列化方式不统一造成的问题。 |
11
shawndev 2020-06-15 09:53:18 +08:00
prettyprinted 设置不同
|
12
jifengg 2020-06-16 11:03:27 +08:00
我就喜欢对整个 body 签名的这种,不用管什么参数排序的。
|