GO 实现一个把结构体做 Sign 签名

把结构体按照 tag json的 sort.Sort(sort.StringSlice([]string{"tag_json_1", "tag_json_2", "tag_json_3"}))
拼接成 key1=a&key2=b 结尾拼接一个 &secret=mysecret 后 进行 md5

package sign

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "reflect"
    "sort"
    "strconv"
)

// GetSign get the sign info
func GetSign(data interface{}, appSecret string) string {
    md5ctx := md5.New()

    switch v := reflect.ValueOf(data); v.Kind() {
    case reflect.String:
        md5ctx.Write([]byte(v.String() + appSecret))
        return hex.EncodeToString(md5ctx.Sum(nil))
    case reflect.Struct:
        orderStr := StructToMapSing(v.Interface(), appSecret)
        md5ctx.Write([]byte(orderStr))
        return hex.EncodeToString(md5ctx.Sum(nil))
    case reflect.Ptr:
        originType := v.Elem().Type()
        if originType.Kind() != reflect.Struct {
            return ""
        }
        dataType := reflect.TypeOf(data).Elem()
        dataVal := v.Elem()
        orderStr := buildOrderStr(dataType, dataVal, appSecret)
        md5ctx.Write([]byte(orderStr))
        return hex.EncodeToString(md5ctx.Sum(nil))
    default:
        return ""
    }
}
func buildOrderStr(t reflect.Type, v reflect.Value, appSecret string) (returnStr string) {
    keys := make([]string, 0, t.NumField())

    var data = make(map[string]interface{})
    for i := 0; i < t.NumField(); i++ {
        if t.Field(i).Tag.Get("json") == "sign" {
            continue
        }
        data[t.Field(i).Tag.Get("json")] = v.Field(i).Interface()

        keys = append(keys, t.Field(i).Tag.Get("json"))
    }

    sort.Sort(sort.StringSlice(keys))

    var buf bytes.Buffer
    for _, k := range keys {
        if data[k] == "" {
            continue
        }
        if buf.Len() > 0 {
            buf.WriteByte('&')
        }

        buf.WriteString(k)
        buf.WriteByte('=')
        switch vv := data[k].(type) {
        case string:
            buf.WriteString(vv)
        case int:
        case int8:
        case int16:
        case int32:
        case int64:
            buf.WriteString(strconv.FormatInt(int64(vv), 10))
        default:
            continue
        }
    }

    buf.WriteString("&secret=" + appSecret)
    returnStr = buf.String()

    return returnStr
}

func StructToMapSing(content interface{}, appSecret string) (returnStr string) {

    t := reflect.TypeOf(content)
    v := reflect.ValueOf(content)

    returnStr = buildOrderStr(t, v, appSecret)

    return returnStr
}

使用

test := struct {
   Test string
}{Test: "你好啊"}

signString := sign.GetSign(test, "testsecret")

fmt.Println(signString)
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 2

这代码量比PHP多不少

4年前 评论
不忘初心 (楼主) 4年前
不忘初心

比较要注意的地方就是 reflect.Struct 和 reflect.Ptr 一个是结构体, 另一个是指针地址指到的结构体, 第二个需要多判断和处理一次

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!