package meituan import ( "crypto/hmac" "crypto/md5" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "net/http" "sort" "strings" "time" "repository.lenntc.com/lenntc/third-platform-sdk/util" ) type Sign struct { AppKey string // 应用key AppSecret string // 应用秘钥 } func newSign(appKey, appSecret string) *Sign { return &Sign{ AppKey: appKey, AppSecret: appSecret, } } func (s *Sign) BuildHeader(methodType string, uri string, data map[string]any) map[string]string { headers := map[string]string{ SCaApp: s.AppKey, // 应用app_key SCaTimestamp: fmt.Sprintf("%d", time.Now().UnixMilli()), // 请求发起时间戳(毫秒),有效时1分钟 SCaSignatureHeaders: "S-Ca-Timestamp,S-Ca-App", // 将需要签名的header ContentMd5: s.contentMD5(methodType, data), // body数据Md5加密 //"Content-Type": "application/json", } headers[SCaSignature] = s.GetSign(methodType, uri, data, headers) return headers } func (s *Sign) GetSign(methodType string, uri string, data map[string]any, signHeaders map[string]string) string { httpMethod := s.httpMethod(methodType) contentMD5 := s.contentMD5(methodType, data) headers := s.headers(signHeaders) url := s.url(methodType, uri, data) strSign := httpMethod + "\n" + contentMD5 + "\n" + headers + url hm := hmac.New(sha256.New, []byte(s.AppSecret)) hm.Write([]byte(strSign)) signStr := base64.StdEncoding.EncodeToString(hm.Sum(nil)) return signStr } // 请求方式大写 func (s *Sign) httpMethod(methodType string) string { return strings.ToUpper(methodType) } // 请求参数执行base64+md5的值 func (s *Sign) contentMD5(methodType string, data map[string]any) string { methodType = s.httpMethod(methodType) if (methodType == http.MethodPost || methodType == http.MethodPut) && data != nil { dataByte, _ := json.Marshal(data) h := md5.New() h.Write(dataByte) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } else { return "" } } // 签名计算Header的Key拼接 func (s *Sign) headers(signHeaders map[string]string) string { var str = "" // key排序 sortData := sort.StringSlice{} for k := range signHeaders { if k != SCaSignature && k != SCaSignatureHeaders && k != ContentMd5 { sortData = append(sortData, k) } } sortData.Sort() for _, k := range sortData { str += k + ":" + signHeaders[k] + "\n" } return str } // url拼接 // post直接返回path,get有参数的情况下拼接url func (s *Sign) url(methodType, uri string, data map[string]any) string { var query = "" methodType = s.httpMethod(methodType) // key排序 sortData := sort.StringSlice{} for k := range data { sortData = append(sortData, k) } sortData.Sort() if len(sortData) > 0 && methodType == http.MethodGet { for num, key := range sortData { value, err := util.ToString(data[key]) if err != nil { return "" } str1 := "" if len(sortData)-1 != num { str1 = "&" } if len(value) > 0 { query += fmt.Sprintf("%s=%s", key, value) } else { query += key } query += str1 } } return fmt.Sprintf("%s%s", uri, query) }