package dx import ( "context" "crypto/md5" "encoding/hex" "sort" "strings" "time" "github.com/gogf/gf/v2/frame/g" ) const ( // DefaultBaseURL 电信API基础地址 DefaultBaseURL = "https://cmp-api.ctwing.cn:20164" ) // GetTimestampGMT 返回 GMT 时区的 yyyyMMddHHmmss 格式时间戳 func GetTimestampGMT() string { return time.Now().UTC().Format("20060102150405") } // OrderParams 将 URL params 按 key 字典序排序 // 输入如 "b=1&c=2&a=1",输出 "a=1&b=1&c=2" func OrderParams(params string) (string, error) { if params == "" { return "", nil } kvs := strings.Split(params, "&") m := make(map[string]string, len(kvs)) for _, kv := range kvs { idx := strings.Index(kv, "=") if idx < 0 { continue } m[kv[:idx]] = kv[idx+1:] } keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) var parts []string for _, k := range keys { parts = append(parts, k+"="+m[k]) } return strings.Join(parts, "&"), nil } // SignMD5 对 reqStr 做 MD5 加密,返回小写十六进制字符串 func SignMD5(reqStr string) string { h := md5.Sum([]byte(reqStr)) return strings.ToLower(hex.EncodeToString(h[:])) } // BuildSign 构造签名:params 排序后拼接 params+body+secretKey+timestamp 再 MD5 // 注意:与参考项目一致,对 MD5 结果再做一次 hex 编码 func BuildSign(params, body, secretKey, timestamp string) (string, error) { ordered, err := OrderParams(params) if err != nil { return "", err } reqStr := ordered + body + secretKey + timestamp md5Str := SignMD5(reqStr) // 对 MD5 结果再做一次 hex 编码(与参考项目一致) hexStr := hex.EncodeToString([]byte(md5Str)) return hexStr, nil } // BuildSignWithDebug 构造签名并输出调试信息 func BuildSignWithDebug(ctx context.Context, params, body, secretKey, timestamp, appKey string) (string, error) { ordered, err := OrderParams(params) if err != nil { return "", err } reqStr := ordered + body + secretKey + timestamp maskedSecret := secretKey g.Log().Debugf(ctx, "[签名调试] AppKey: %s", appKey) g.Log().Debugf(ctx, "[签名调试] SecretKey: %s", maskedSecret) g.Log().Debugf(ctx, "[签名调试] Timestamp: %s", timestamp) g.Log().Debugf(ctx, "[签名调试] 排序后参数: %s", ordered) g.Log().Debugf(ctx, "[签名调试] Body: '%s'", body) g.Log().Debugf(ctx, "[签名调试] 签名原串: %s%s[SecretKey]%s", ordered, body, timestamp) md5Str := SignMD5(reqStr) g.Log().Debugf(ctx, "[签名调试] MD5结果: %s", md5Str) // 对 MD5 结果再做一次 hex 编码 hexStr := hex.EncodeToString([]byte(md5Str)) g.Log().Debugf(ctx, "[签名调试] 最终签名(hex编码后): %s", hexStr) return hexStr, nil }