package activityclient import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "strconv" "strings" "time" ) // 与 activity-public-server middleware/svcauth 协议保持一致: // // X-Svc-AppId : 调用方 appId // X-Svc-Ts : 请求生成的 Unix 秒(服务端校验 ±300s) // X-Svc-Sign : HMAC_SHA256(canonical, secret) 的 hex 小写 // // canonical 串结构("\n" 分隔): // // appId // ts // METHOD // 大写 // path // URL.Path,不含 query // rawQuery // URL.RawQuery 原样,不重排序 // sha256_hex(body) // 空 body 也参与运算 const ( headerSvcAppId = "X-Svc-AppId" headerSvcTs = "X-Svc-Ts" headerSvcSign = "X-Svc-Sign" ) // BuildSvcHeaders 生成服务间调用鉴权头。 // method/path/rawQuery 必须与服务端 c.Request 上看到的一致; // body 传原始字节(GET 等无 body 接口传 nil)。 // appId 或 secret 为空时返回 nil,调用方按未签名处理。 func BuildSvcHeaders(appId, secret, method, path, rawQuery string, body []byte) map[string]string { if appId == "" || secret == "" { return nil } ts := strconv.FormatInt(time.Now().Unix(), 10) return map[string]string{ headerSvcAppId: appId, headerSvcTs: ts, headerSvcSign: computeSvcSign(secret, appId, ts, strings.ToUpper(method), path, rawQuery, hashBody(body)), } } // hashBody 计算 body 的 sha256 hex;nil/空 body 也返回 sha256("") 的 hex func hashBody(body []byte) string { sum := sha256.Sum256(body) return hex.EncodeToString(sum[:]) } // computeSvcSign 按 canonical 串拼接后做 HMAC-SHA256 func computeSvcSign(secret, appId, ts, method, path, rawQuery, bodyHash string) string { h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(appId)) h.Write([]byte{'\n'}) h.Write([]byte(ts)) h.Write([]byte{'\n'}) h.Write([]byte(method)) h.Write([]byte{'\n'}) h.Write([]byte(path)) h.Write([]byte{'\n'}) h.Write([]byte(rawQuery)) h.Write([]byte{'\n'}) h.Write([]byte(bodyHash)) return hex.EncodeToString(h.Sum(nil)) }