package bopx import ( "context" "crypto/md5" "fmt" "sort" "strings" "code.yun.ink/pkg/convx" "github.com/yuninks/loggerx" ) // 签名规则 // 1.除掉不参与签名的用户参数 // 1.所有参数的key根据字典排序 // 2.根据key=val&key2=val2的格式组装字符串 // 3.后面拼接用户签名key `&key=xxxx`得道新字符串 // 4.把新字符串用md5加密并转大写的道签名的值 // 缺点 // 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) } // 排序 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 := convx.ToString(params[v]) str = str + v + "=" + val } str = str + "&key=" + signKey data := []byte(str) has := md5.Sum(data) md5str1 := fmt.Sprintf("%x", has) // []byte转16进制 sign = strings.ToUpper(md5str1) l.logger.Infof(ctx, "bopx sign Str:%s sign:%s", str, sign) return sign, nil } func (l *apix) Verify(ctx context.Context, signKey string, 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(ctx, signKey, params) if err != nil { return err } if sitn_str != g_sign { return ErrorSignFail } return nil }