优化签名规则

This commit is contained in:
Yun
2025-10-12 18:41:05 +08:00
parent e26d03a35a
commit 70e32e7d8e
9 changed files with 426 additions and 44 deletions
+1
View File
@@ -0,0 +1 @@
*.log
+34 -24
View File
@@ -1,37 +1,49 @@
package bopx package bopx
import ( import (
"context"
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
"code.yun.ink/pkg/convx" "code.yun.ink/pkg/convx"
"github.com/yuninks/loggerx"
) )
// 缺点
// 1.值必须是字符串,数组/对象这些不允许,或者需要通过一定规则转成字符串
type apix struct {
ingoreKey []string
signKey string
}
func NewApi(ignoreKey []string, signKey string) *apix {
return &apix{
ingoreKey: ignoreKey,
signKey: signKey,
}
}
// 签名规则 // 签名规则
// 1.除掉不参与签名的用户参数 // 1.除掉不参与签名的用户参数
// 1.所有参数的key根据字典排序 // 1.所有参数的key根据字典排序
// 2.根据key=val&key2=val2的格式组装字符串 // 2.根据key=val&key2=val2的格式组装字符串
// 3.后面拼接用户签名key `&key=xxxx`得道新字符串 // 3.后面拼接用户签名key `&key=xxxx`得道新字符串
// 4.把新字符串用md5加密并转大写的道签名的值 // 4.把新字符串用md5加密并转大写的道签名的值
func (l *apix) GetSign(params map[string]interface{}) (sign string, err error) {
for _, val := range l.ingoreKey { // 缺点
// 1.值必须是字符串,数组/对象这些不允许,或者需要通过一定规则转成字符串
type apix struct {
logger loggerx.LoggerInterface
ignoreKeys []string
}
func NewApi(opts ...Option) *apix {
options := newOptions(opts...)
return &apix{
logger: options.logger,
ignoreKeys: options.ignoreKeys,
}
}
// 计算签名值
func (l *apix) GetSign(ctx context.Context, signKey string, params map[string]any) (sign string, err error) {
if signKey == "" {
return "", ErrorSignKeyIsEmpty
}
if len(params) == 0 {
return "", ErrorSignParamIsEmpty
}
for _, val := range l.ignoreKeys {
delete(params, val) delete(params, val)
} }
@@ -48,21 +60,19 @@ func (l *apix) GetSign(params map[string]interface{}) (sign string, err error) {
if k > 0 { if k > 0 {
str = str + "&" str = str + "&"
} }
val, err := convx.ToString(params[v]) val := convx.ToString(params[v])
if err != nil {
return "", err
}
str = str + v + "=" + val str = str + v + "=" + val
} }
str = str + "&key=" + l.signKey str = str + "&key=" + signKey
data := []byte(str) data := []byte(str)
has := md5.Sum(data) has := md5.Sum(data)
md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 md5str1 := fmt.Sprintf("%x", has) // []byte转16进制
sign = strings.ToUpper(md5str1) sign = strings.ToUpper(md5str1)
l.logger.Infof(ctx, "bopx sign Str:%s sign:%s", str, sign)
return sign, nil return sign, nil
} }
func (l *apix) Verify(params map[string]interface{}) error { func (l *apix) Verify(ctx context.Context, signKey string, params map[string]interface{}) error {
sign, ok := params["sign"] sign, ok := params["sign"]
if !ok { if !ok {
@@ -72,7 +82,7 @@ func (l *apix) Verify(params map[string]interface{}) error {
if !ok { if !ok {
return ErrorSignMustBeString return ErrorSignMustBeString
} }
g_sign, err := l.GetSign(params) g_sign, err := l.GetSign(ctx, signKey, params)
if err != nil { if err != nil {
return err return err
} }
+192
View File
@@ -0,0 +1,192 @@
package bopx_test
import (
"context"
"testing"
"code.yun.ink/pkg/bopx"
"github.com/stretchr/testify/assert"
)
// TestApiGetSign 测试API签名生成
func TestApiGetSign(t *testing.T) {
// 测试用例1: 基本参数签名
params := map[string]interface{}{
"name": "huang",
"age": 18,
}
api := bopx.NewApi()
sign, err := api.GetSign(context.Background(), "huangxinyun", params)
if err != nil {
t.Errorf("GetSign returned error: %v", err)
}
expectedSign := "F84C5DF671D8279B57AC6EED2C140407" // 根据算法计算得出的预期值
if sign != expectedSign {
t.Errorf("GetSign() = %v, want %v", sign, expectedSign)
}
// 记录生成的签名值
t.Logf("Generated sign: %s", sign)
}
// TestApiVerify 测试API签名验证
func TestApiVerify(t *testing.T) {
// 测试用例1: 正确签名验证
params := map[string]interface{}{
"name": "huang",
"age": 18,
}
api := bopx.NewApi()
sign, err := api.GetSign(context.Background(), "huangxinyun", params)
if err != nil {
t.Errorf("GetSign returned error: %v", err)
}
params["sign"] = sign
err = api.Verify(context.Background(), "huangxinyun", params)
if err != nil {
t.Errorf("Verify returned error: %v", err)
}
// 测试用例2: 签名参数不存在
paramsWithoutSign := map[string]interface{}{
"name": "huang",
"age": 18,
}
err = api.Verify(context.Background(), "huangxinyun", paramsWithoutSign)
if err != bopx.ErrorSignParamNotExist {
t.Errorf("Verify should return ErrorSignParamNotExist, got: %v", err)
}
// 测试用例3: 签名参数不是字符串
paramsWithInvalidSign := map[string]interface{}{
"name": "huang",
"age": 18,
"sign": 12345, // 非字符串类型
}
err = api.Verify(context.Background(), "huangxinyun", paramsWithInvalidSign)
if err != bopx.ErrorSignMustBeString {
t.Errorf("Verify should return ErrorSignMustBeString, got: %v", err)
}
// 测试用例4: 签名不匹配
paramsWithWrongSign := map[string]interface{}{
"name": "huang",
"age": 18,
"sign": "WRONGSIGN",
}
err = api.Verify(context.Background(), "huangxinyun", paramsWithWrongSign)
if err != bopx.ErrorSignFail {
t.Errorf("Verify should return ErrorSignFail, got: %v", err)
}
}
// TestApiIgnoreKeys 测试忽略键功能
func TestApiIgnoreKeys(t *testing.T) {
params := map[string]interface{}{
"name": "huang",
"age": 18,
"platform_key": "ignored",
"sign": "ignored",
"key": "ignored",
}
api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key"))
sign, err := api.GetSign(context.Background(), "huangxinyun", params)
if err != nil {
t.Errorf("GetSign returned error: %v", err)
}
// 验证忽略的键不影响签名结果
paramsWithoutIgnored := map[string]interface{}{
"name": "huang",
"age": 18,
}
signWithoutIgnored, err := api.GetSign(context.Background(), "huangxinyun", paramsWithoutIgnored)
if err != nil {
t.Errorf("GetSign returned error: %v", err)
}
if sign != signWithoutIgnored {
t.Errorf("Signatures with/without ignored keys should be equal. With ignored: %s, without: %s", sign, signWithoutIgnored)
}
}
// TestApiEmptyParams 测试空参数
func TestApiEmptyParams(t *testing.T) {
params := map[string]interface{}{}
api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key"))
sign, err := api.GetSign(context.Background(), "huangxinyun", params)
assert.NotNil(t, err)
assert.Equal(t, bopx.ErrorSignParamIsEmpty, err)
assert.Equal(t, "", sign)
}
// TestApiSpecialValues 测试特殊值
func TestApiSpecialValues(t *testing.T) {
params := map[string]interface{}{
"empty_string": "",
"nil_value": nil,
"zero": 0,
"special_chars": "!@#$%^&*()_+-=[]{}|;':\",./<>?",
}
api := bopx.NewApi(bopx.WithIgnoreKeys("platform_key", "sign", "key"))
sign, err := api.GetSign(context.Background(), "testkey", params)
if err != nil {
t.Errorf("GetSign returned error: %v", err)
}
if sign == "" {
t.Error("Sign should not be empty for special values")
}
params["sign"] = sign
err = api.Verify(context.Background(), "testkey", params)
if err != nil {
t.Errorf("Verify returned error: %v", err)
}
}
// TestApiConsistentResults 测试签名一致性
func TestApiConsistentResults(t *testing.T) {
params1 := map[string]interface{}{
"c": "third",
"a": "first",
"b": "second",
}
params2 := map[string]interface{}{
"b": "second",
"c": "third",
"a": "first",
}
api := bopx.NewApi()
sign1, err := api.GetSign(context.Background(), "consistentkey", params1)
if err != nil {
t.Errorf("GetSign for params1 returned error: %v", err)
}
sign2, err := api.GetSign(context.Background(), "consistentkey", params2)
if err != nil {
t.Errorf("GetSign for params2 returned error: %v", err)
}
// 由于参数排序,两种不同顺序的map应该产生相同的签名
if sign1 != sign2 {
t.Errorf("Signatures should be consistent regardless of parameter order. sign1: %s, sign2: %s", sign1, sign2)
}
}
+3
View File
@@ -6,4 +6,7 @@ var (
ErrorSignParamNotExist = errors.New("签名参数不存在") ErrorSignParamNotExist = errors.New("签名参数不存在")
ErrorSignMustBeString = errors.New("sign必须是字符串") ErrorSignMustBeString = errors.New("sign必须是字符串")
ErrorSignFail = errors.New("验签失败") ErrorSignFail = errors.New("验签失败")
ErrorSignParamEmpty = errors.New("签名参数为空")
ErrorSignParamIsEmpty = errors.New("签名参数不能为空")
ErrorSignKeyIsEmpty = errors.New("签名key不能为空")
) )
+35 -1
View File
@@ -2,4 +2,38 @@ module code.yun.ink/pkg/bopx
go 1.20 go 1.20
require code.yun.ink/pkg/convx v1.0.1 require (
code.yun.ink/pkg/convx v1.0.3
github.com/stretchr/testify v1.8.3
github.com/yuninks/loggerx v1.0.13
)
require (
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+89 -2
View File
@@ -1,2 +1,89 @@
code.yun.ink/pkg/convx v1.0.1 h1:T6yIVqyC1nQc9CO0C7iHn5rs7GxbaulmrJtxwg95q9Y= code.yun.ink/pkg/convx v1.0.3 h1:pH8dUOgsoaBYVQ3+4C2+uVua561nDxq6/GpaQ9wnCew=
code.yun.ink/pkg/convx v1.0.1/go.mod h1:6xqmUend1kwarRvJ0TQlfzzS4QCWdRrXQiUY/ggzYqo= code.yun.ink/pkg/convx v1.0.3/go.mod h1:6xqmUend1kwarRvJ0TQlfzzS4QCWdRrXQiUY/ggzYqo=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuninks/loggerx v1.0.13 h1:NVb0oHoZeJ59ZAaU5HqcpY7TfZlLaXQEzkRhdOTthiA=
github.com/yuninks/loggerx v1.0.13/go.mod h1:+QFoywQ1ICh4v40zj6OHM8GBZHEqV0yvRbkZjZUe2o4=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+46
View File
@@ -0,0 +1,46 @@
package bopx
import (
"context"
"github.com/yuninks/loggerx"
)
type Options struct {
logger loggerx.LoggerInterface // 日志接口
ignoreKeys []string // 忽略签名的key
}
type Option func(*Options)
func newOptions(opts ...Option) *Options {
options := defaultOptions()
for _, opt := range opts {
opt(options)
}
return options
}
func defaultOptions() *Options {
return &Options{
logger: loggerx.NewLogger(
context.Background(),
loggerx.SetEscapeHTML(false),
),
ignoreKeys: []string{
"sign",
},
}
}
func WithLogger(logger loggerx.LoggerInterface) Option {
return func(o *Options) {
o.logger = logger
}
}
func WithIgnoreKeys(keys ...string) Option {
return func(o *Options) {
o.ignoreKeys = keys
}
}
+22 -14
View File
@@ -2,28 +2,39 @@
package bopx package bopx
import ( import (
"context"
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
"code.yun.ink/pkg/convx" "code.yun.ink/pkg/convx"
"github.com/yuninks/loggerx"
) )
type platform struct { type platform struct {
ingoreKey []string ingoreKeys []string
signKey string logger loggerx.LoggerInterface
} }
func NewPlatform(ignoreKey []string, signKey string) *platform { func NewPlatform(opts ...Option) *platform {
options := newOptions(opts...)
return &platform{ return &platform{
ingoreKey: ignoreKey, ingoreKeys: options.ignoreKeys,
signKey: signKey, logger: options.logger,
} }
} }
func (l *platform) GetSign(params map[string]interface{}) (sign string, err error) { func (l *platform) GetSign(ctx context.Context, signKey string, params map[string]any) (sign string, err error) {
for _, val := range l.ingoreKey {
if signKey == "" {
return "", ErrorSignKeyIsEmpty
}
if len(params) == 0 {
return "", ErrorSignParamIsEmpty
}
for _, val := range l.ingoreKeys {
delete(params, val) delete(params, val)
} }
@@ -40,13 +51,10 @@ func (l *platform) GetSign(params map[string]interface{}) (sign string, err erro
if k > 0 { if k > 0 {
str = str + "&" str = str + "&"
} }
val, err := convx.ToString(params[v]) val := convx.ToString(params[v])
if err != nil {
return "", err
}
str = str + v + "=" + val str = str + v + "=" + val
} }
str = str + "&key=" + l.signKey str = str + "&key=" + signKey
data := []byte(str) data := []byte(str)
has := md5.Sum(data) has := md5.Sum(data)
md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 md5str1 := fmt.Sprintf("%x", has) // []byte转16进制
@@ -54,7 +62,7 @@ func (l *platform) GetSign(params map[string]interface{}) (sign string, err erro
return sign, nil return sign, nil
} }
func (l *platform) VerifySign(params map[string]interface{}) error { func (l *platform) VerifySign(ctx context.Context, signKey string, params map[string]interface{}) error {
sign, ok := params["sign"] sign, ok := params["sign"]
if !ok { if !ok {
return ErrorSignParamNotExist return ErrorSignParamNotExist
@@ -63,7 +71,7 @@ func (l *platform) VerifySign(params map[string]interface{}) error {
if !ok { if !ok {
return ErrorSignMustBeString return ErrorSignMustBeString
} }
g_sign, err := l.GetSign(params) g_sign, err := l.GetSign(ctx, signKey, params)
if err != nil { if err != nil {
return err return err
} }
+4 -3
View File
@@ -1,6 +1,7 @@
package bopx_test package bopx_test
import ( import (
"context"
"testing" "testing"
"code.yun.ink/pkg/bopx" "code.yun.ink/pkg/bopx"
@@ -16,14 +17,14 @@ func TestGetSign(t *testing.T) {
// delete(params, "sign") // delete(params, "sign")
// delete(params, "key") // delete(params, "key")
s := bopx.NewPlatform([]string{"platform_key", "sign", "key"}, "huangxinyun") s := bopx.NewPlatform()
sign, err := s.GetSign(params) sign, err := s.GetSign(context.Background(), "huangxinyun", params)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
t.Log(sign) t.Log(sign)
params["sign"] = sign params["sign"] = sign
err = s.VerifySign(params) err = s.VerifySign(context.Background(), "huangxinyun", params)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }