API 鉴权与签名机制
本文说明 PartnerShare 开放接口的服务端鉴权方式。接入方需要在每次请求中携带 API Key、秒级时间戳和签名,PartnerShare 会基于 API Secret 重新计算签名并校验请求合法性,避免接口被伪造、重放或越权调用。
1. 概述 #
PartnerShare 开放接口默认使用 API Key + API Secret + Timestamp + Signature 的方式完成鉴权。API Key 用于识别调用方产品,API Secret 仅用于服务端生成签名,不会直接随请求发送。
通过 X-Api-Key 定位产品和租户,确保请求来自已授权产品。
签名由 API Secret 生成,攻击者即使知道 API Key,也无法构造合法签名。
X-Api-Timestamp 仅在 5 分钟时间窗内有效,过期请求会被拒绝。
API Secret 必须保存在服务端,不允许暴露在浏览器、小程序、移动端 App、公开仓库或共享 Postman 环境中。
2. 获取 API Key 和 API Secret #
请在 PartnerShare 后台进入对应产品的开发者集成或高级设置页面,获取该产品的 API Key 和 API Secret。

API Key 用于请求头传输,标识调用方产品;API Secret 只用于本地计算签名,不参与明文传输。
3. 请求头约定 #
调用需要鉴权的开放接口时,请在 Header 中携带以下参数:
| Header | 必填 | 说明 |
|---|---|---|
X-Api-Key | 是 | PartnerShare 分配给产品的 API Key,用于识别调用方产品。 |
X-Api-Timestamp | 是 | 秒级时间戳。服务端会校验时间戳是否在有效时间窗内。 |
X-Api-Sign | 是 | 按本文签名规则生成的 SHA256 签名。 |
Content-Type | 是 | 推荐使用 application/json。 |
Header 示例:
POST /api/open/v1/track/conversion HTTP/1.1
Host: api-service.partnershare.net
Content-Type: application/json
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: 8473ee71d083d9d1650c0e9081b5777d5b6cde2508521d5322d603a007214afd
4. 签名规则 #
PartnerShare 的签名只使用请求参数的字段名参与计算,不使用字段值参与计算;Header 字段也不参与签名。
Product_Key 会按 product_key 参与签名。SORT_NATURAL。extra&product_key&target_product_key&user_id。字段名串 + timestamp + api_secret。4.1 签名公式 #
sha256(sorted_lowercase_param_keys_joined_by_ampersand + timestamp + api_secret)
4.2 示例推导 #
请求参数:
{
"product_key": "your_product_key",
"target_product_key": "target_product_key",
"user_id": "user_10001",
"extra": {
"locale": "zh"
}
}
参与签名的字段名:
product_key
target_product_key
user_id
extra
排序并拼接后:
extra&product_key&target_product_key&user_id
假设:
timestamp = 1776677721
api_secret = sk_your_api_secret
最终待签名字符串:
extra&product_key&target_product_key&user_id1776677721sk_your_api_secret
5. 签名示例 #
5.1 JavaScript #
function makeSign(params, timestamp, apiSecret) {
const keys = Object.keys(params)
.map((key) => key.toLowerCase())
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
const signString = keys.join('&') + timestamp + apiSecret;
return CryptoJS.SHA256(signString).toString(CryptoJS.enc.Hex);
}
5.2 PHP #
<?php
function makeSign(array $params, string $timestamp, string $apiSecret): string
{
$keys = array_map('strtolower', array_keys($params));
sort($keys, SORT_NATURAL);
$signString = implode('&', $keys) . $timestamp . $apiSecret;
return hash('sha256', $signString);
}
5.3 Go #
package main
import (
"crypto/sha256"
"fmt"
"sort"
"strings"
)
func MakeSign(params map[string]interface{}, timestamp string, apiSecret string) string {
keys := make([]string, 0, len(params))
for key := range params {
keys = append(keys, strings.ToLower(key))
}
sort.Strings(keys)
signString := strings.Join(keys, "&") + timestamp + apiSecret
sum := sha256.Sum256([]byte(signString))
return fmt.Sprintf("%x", sum)
}
5.4 Python #
import hashlib
def make_sign(params: dict, timestamp: str, api_secret: str) -> str:
keys = sorted([key.lower() for key in params.keys()])
sign_string = "&".join(keys) + timestamp + api_secret
return hashlib.sha256(sign_string.encode("utf-8")).hexdigest()
6. 完整请求示例 #
以下示例展示一次注册事件回传请求的 Header 和 Body 结构。不同接口的 Body 字段可能不同,但签名生成方式保持一致。
POST /api/open/v1/track/conversion HTTP/1.1
Host: api-service.partnershare.net
Content-Type: application/json
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: 8473ee71d083d9d1650c0e9081b5777d5b6cde2508521d5322d603a007214afd
{
"event_name": "signup",
"invited_user_id": "user_10001",
"invite_code": "abc123"
}
参与签名的字段名为 event_name、invited_user_id、invite_code,排序后拼接为 event_name&invite_code&invited_user_id。
7. 常见错误与排查 #
7.1 为什么提示“API Key 或签名不能为空”? #
通常是请求头缺少 X-Api-Key、X-Api-Timestamp 或 X-Api-Sign。请确认 Header 名称拼写正确,并且请求没有被网关或代理移除自定义 Header。
7.2 为什么提示“签名错误”? #
请重点检查:是否使用 API Secret 而不是 API Key 参与签名;字段名是否转为小写;字段名排序是否一致;参与签名的字段是否与实际请求 Body 顶层字段完全一致。
7.3 为什么本地签名正确,线上仍然失败? #
常见原因是线上请求参数被序列化格式改变,例如本地使用 JSON,线上使用表单;或反向代理改变了请求 Body。建议先打印实际发送给 PartnerShare 的 Body 顶层字段名进行对比。
7.4 时间戳有效期是多久? #
当前时间戳有效期为 5 分钟。请使用秒级时间戳,并确保服务器时间与标准时间保持同步。
7.5 API Secret 可以放在前端吗? #
不可以。API Secret 一旦暴露,任何人都可以伪造合法请求。请始终在服务端生成签名,前端只调用自己的业务服务端。
8. 最佳实践 #
- 只在服务端保存 API Secret,不写入前端代码、移动端包体或公开配置。
- 每次请求都重新生成时间戳和签名,不复用历史签名。
- 签名前记录参与签名的字段名列表,便于排查联调问题。
- 生产环境和测试环境使用不同的 API Key 与 API Secret。
- 如怀疑 API Secret 泄露,应立即在后台重置密钥并更新服务端配置。