commit e26d03a35a76f97466e5ac5fe89a8fcefb3b6b16 Author: Yun Date: Mon Nov 4 12:10:36 2024 +0800 BOP的签名 diff --git a/api.go b/api.go new file mode 100644 index 0000000..3a890b5 --- /dev/null +++ b/api.go @@ -0,0 +1,84 @@ +package bopx + +import ( + "crypto/md5" + "fmt" + "sort" + "strings" + + "code.yun.ink/pkg/convx" +) + +// 缺点 +// 1.值必须是字符串,数组/对象这些不允许,或者需要通过一定规则转成字符串 + +type apix struct { + ingoreKey []string + signKey string +} + +func NewApi(ignoreKey []string, signKey string) *apix { + return &apix{ + ingoreKey: ignoreKey, + signKey: signKey, + } +} + +// 签名规则 +// 1.除掉不参与签名的用户参数 +// 1.所有参数的key根据字典排序 +// 2.根据key=val&key2=val2的格式组装字符串 +// 3.后面拼接用户签名key `&key=xxxx`得道新字符串 +// 4.把新字符串用md5加密并转大写的道签名的值 +func (l *apix) GetSign(params map[string]interface{}) (sign string, err error) { + for _, val := range l.ingoreKey { + delete(params, val) + } + + // 排序 + keys := make([]string, len(params)) + i := 0 + for k := range params { + keys[i] = k + i++ + } + sort.Strings(keys) + var str string + for k, v := range keys { + if k > 0 { + str = str + "&" + } + val, err := convx.ToString(params[v]) + if err != nil { + return "", err + } + str = str + v + "=" + val + } + str = str + "&key=" + l.signKey + data := []byte(str) + has := md5.Sum(data) + md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 + sign = strings.ToUpper(md5str1) + return sign, nil +} + +func (l *apix) Verify(params map[string]interface{}) error { + + sign, ok := params["sign"] + if !ok { + return ErrorSignParamNotExist + } + sitn_str, ok := sign.(string) + if !ok { + return ErrorSignMustBeString + } + g_sign, err := l.GetSign(params) + if err != nil { + return err + } + if sitn_str != g_sign { + return ErrorSignFail + } + + return nil +} diff --git a/errorx.go b/errorx.go new file mode 100644 index 0000000..f5d1602 --- /dev/null +++ b/errorx.go @@ -0,0 +1,9 @@ +package bopx + +import "errors" + +var ( + ErrorSignParamNotExist = errors.New("签名参数不存在") + ErrorSignMustBeString = errors.New("sign必须是字符串") + ErrorSignFail = errors.New("验签失败") +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..be0dd71 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module code.yun.ink/pkg/bopx + +go 1.20 + +require code.yun.ink/pkg/convx v1.0.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fe3664f --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +code.yun.ink/pkg/convx v1.0.1 h1:T6yIVqyC1nQc9CO0C7iHn5rs7GxbaulmrJtxwg95q9Y= +code.yun.ink/pkg/convx v1.0.1/go.mod h1:6xqmUend1kwarRvJ0TQlfzzS4QCWdRrXQiUY/ggzYqo= diff --git a/platform.go b/platform.go new file mode 100644 index 0000000..c1b229f --- /dev/null +++ b/platform.go @@ -0,0 +1,75 @@ +// 这个方法适配BOP的签名 +package bopx + +import ( + "crypto/md5" + "fmt" + "sort" + "strings" + + "code.yun.ink/pkg/convx" +) + +type platform struct { + ingoreKey []string + signKey string +} + +func NewPlatform(ignoreKey []string, signKey string) *platform { + return &platform{ + ingoreKey: ignoreKey, + signKey: signKey, + } +} + +func (l *platform) GetSign(params map[string]interface{}) (sign string, err error) { + for _, val := range l.ingoreKey { + delete(params, val) + } + + // 排序 + keys := make([]string, len(params)) + i := 0 + for k := range params { + keys[i] = k + i++ + } + sort.Strings(keys) + var str string + for k, v := range keys { + if k > 0 { + str = str + "&" + } + val, err := convx.ToString(params[v]) + if err != nil { + return "", err + } + str = str + v + "=" + val + } + str = str + "&key=" + l.signKey + data := []byte(str) + has := md5.Sum(data) + md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 + sign = strings.ToUpper(md5str1) + return sign, nil +} + +func (l *platform) VerifySign(params map[string]interface{}) error { + sign, ok := params["sign"] + if !ok { + return ErrorSignParamNotExist + } + sitn_str, ok := sign.(string) + if !ok { + return ErrorSignMustBeString + } + g_sign, err := l.GetSign(params) + if err != nil { + return err + } + if sitn_str != g_sign { + return ErrorSignFail + } + + return nil +} diff --git a/platform_test.go b/platform_test.go new file mode 100644 index 0000000..332eb54 --- /dev/null +++ b/platform_test.go @@ -0,0 +1,30 @@ +package bopx_test + +import ( + "testing" + + "code.yun.ink/pkg/bopx" +) + +func TestGetSign(t *testing.T) { + params := map[string]interface{}{ + "name": "huang", + "age": 18, + } + + // delete(params, "platform_key") + // delete(params, "sign") + // delete(params, "key") + + s := bopx.NewPlatform([]string{"platform_key", "sign", "key"}, "huangxinyun") + sign, err := s.GetSign(params) + if err != nil { + t.Error(err) + } + t.Log(sign) + params["sign"] = sign + err = s.VerifySign(params) + if err != nil { + t.Error(err) + } +}