- 新增小红书前端模块(启动服务、内容分析、爆款创作、发布记录、技能卡片、拟人设置、AI 助手) - 新增 xhs-agent-desktop 独立桌面 Agent,对接 OMS 任务调度 - 登录页重构,整合微信登录与 OMS JWT 认证 - 订单、渠道、用户中心等页面与 API 增强 Co-authored-by: Cursor <cursoragent@cursor.com>
209 lines
8.0 KiB
Markdown
209 lines
8.0 KiB
Markdown
---
|
||
name: itfx-prefix-script
|
||
description: >-
|
||
Generates InterfaceForward (接口通/itfx) PrefixScript C# for any signature/auth
|
||
algorithm (MD5/SHA/HMAC/RSA/custom). Maps writes to Query/Header/Body field lists
|
||
per downstream interface detail. Use for 前置脚本, PrefixScript, Natasha script.
|
||
---
|
||
|
||
# itfx 接口映射前置脚本生成(通用签名)
|
||
|
||
为 **InterfaceMap → PrefixScript** 生成 Natasha 可执行的 C# 方法体,**按用户描述的任意签名规则**实现,不限于某一服务商。
|
||
|
||
## 何时使用
|
||
|
||
- 生成/修改 **前置脚本**(非 PostfixScript)
|
||
- 第三方 API 需要签名、鉴权头、动态 token、时间戳参与计算等
|
||
- OMS「上游接口 → 映射明细 → 前置脚本」
|
||
|
||
## 执行时机
|
||
|
||
```
|
||
InParamRestructure → ReplacePlaceholder → PrefixScript ← 本 Skill
|
||
→ SerializationBody → HTTP 请求 → PostfixScript
|
||
```
|
||
|
||
| 可用 | 不可用 |
|
||
|------|--------|
|
||
| `obj.OriginalInterfaceMappedInput` | `obj.TargetInterfaceInput`(未序列化) |
|
||
| `obj.QueryFieldList` / `HeaderFieldList` / `FormFieldList` | `obj.TargetInterfaceOutput` |
|
||
| `obj.FixedFieldList` | 改 `InParamTreeList` / 映射树 |
|
||
| `obj.GetAccountFieldValueOrNull(...)` | |
|
||
|
||
## 下游接口明细 ↔ 运行时(写入位置必对齐)
|
||
|
||
| 接口明细 Tab | 运行时列表 | 典型用途 |
|
||
|--------------|------------|----------|
|
||
| Query KV | `obj.QueryFieldList` | URL 参数、签名字段 |
|
||
| Header KV | `obj.HeaderFieldList` | 请求头、Authorization |
|
||
| Body KV(FormUrlEncoded) | `obj.FormFieldList` | 表单字段 |
|
||
| Mapping Body 树 | → `OriginalInterfaceMappedInput` | 映射体(Form/None 类) |
|
||
| Request Body 树(Json/Xml) | → `OriginalInterfaceMappedInput` | JSON/XML Body |
|
||
|
||
**ContentType:** `None(0)` 无 Body;`FormUrlEncoded(1)` Body=FormFieldList;`Json(3)`/`Xml(4)` Body=序列化映射体。
|
||
|
||
## 占位符(ReplacePlaceholder 早于 PrefixScript)
|
||
|
||
| 占位符 | PrefixScript 阶段 |
|
||
|--------|-------------------|
|
||
| `$TimeStamp` / `$DateTime` / `$FromAccount` / `$Url` / `$token` | 通常已替换,直接读字段 Value |
|
||
| `$FromMappingBody` | FormUrlEncoded:可能仍为字面量;None/Json Query:通常已替换为 JSON。**签名用最终 HTTP 参数值,不要用占位符字面量** |
|
||
|
||
## 脚本技术约束
|
||
|
||
- C#,Natasha 动态编译;参数名 **`obj`**(不是 `context`)
|
||
- 仅方法体:无 `using` / `class` / `namespace` / `void Main`
|
||
- 类型 **全限定名**:`System.Security.Cryptography.HMACSHA256`、`Newtonsoft.Json.JsonConvert`
|
||
- 含 `await` 或首行 `//async` → 异步委托
|
||
|
||
---
|
||
|
||
## 通用签名生成流程(任何算法都走此流程)
|
||
|
||
用户未给全规则时,**先向用户确认**缺失项;给全则直接生成。
|
||
|
||
### 1. 从需求提取七要素
|
||
|
||
| 要素 | 问什么 |
|
||
|------|--------|
|
||
| 算法 | MD5 / SHA1 / SHA256 / HMAC-SHA1 / HMAC-SHA256 / HMAC-MD5 / RSA / 自定义 |
|
||
| 签名字符串 | 字段如何拼接、排序、分隔符、是否含 urlPath/body/secret 前缀后缀 |
|
||
| 参与字段 | 哪些 Query/Header/Form/Body JSON 字段;**排除签名字段本身** |
|
||
| 密钥 | 账户字段名(`GetAccountFieldValueOrNull`)或固定参数 |
|
||
| 输出位置 | Query / Header / Form Body / JSON Body 字段名 |
|
||
| 编码 | UTF-8;hex **大写/小写**、Base64、是否 URL 编码 |
|
||
| 特殊 | 空值是否跳过、嵌套 JSON、时间戳单位、是否 double-MD5 等 |
|
||
|
||
### 2. 对照下游接口明细
|
||
|
||
- 签名字段在哪个 Tab → 写入 `QueryFieldList` / `HeaderFieldList` / `FormFieldList` 或改 `OriginalInterfaceMappedInput`
|
||
- 参与签名的业务字段在哪个 Tab → 从**对应列表**读取 Value
|
||
- 账户字段名与服务商配置一致
|
||
|
||
### 3. 取参与签名的参数值(通用原则)
|
||
|
||
**原则:签名字符串中的每个值 = 最终 HTTP 请求里该参数的值。**
|
||
|
||
```csharp
|
||
// 按名读 Query(通用 helper 思路,可内联)
|
||
string GetQueryValue(string name) {
|
||
for (int i = 0; i < obj.QueryFieldList.Count; i++)
|
||
if (obj.QueryFieldList[i].Name == name) return obj.QueryFieldList[i].Value ?? "";
|
||
return "";
|
||
}
|
||
// Header / Form 同理遍历 HeaderFieldList / FormFieldList
|
||
|
||
// JSON Body(ContentType.Json)
|
||
string bodyJson = Newtonsoft.Json.JsonConvert.SerializeObject(obj.OriginalInterfaceMappedInput);
|
||
|
||
// 映射体 JSON:优先读已替换好的 Query/Form 字段;仍为 $FromMappingBody 时再 SerializeObject
|
||
```
|
||
|
||
**常见坑(任何服务商):**
|
||
|
||
- 签名字段(`sign`、`_aop_signature` 等)**不参与**签名字符串
|
||
- 不要读错列表(Query 参数却在 FormFieldList 里找)
|
||
- 不要对已是最终值的字段再 `SerializeObject`(字段顺序/空格会变)
|
||
- JSON 内 `"CHINA SHENZHEN"` 与 URL 编码的 `+` **不是同一字符**,签名用 JSON 原文
|
||
- FormUrlEncoded 阶段 `$FromMappingBody` 可能尚未替换,需 `SerializeObject(OriginalInterfaceMappedInput)` 或读已替换 Value
|
||
|
||
### 4. 常见算法 C# 片段(按文档选用,勿臆造)
|
||
|
||
**MD5 / SHA → hex**
|
||
|
||
```csharp
|
||
var md5 = System.Security.Cryptography.MD5.Create();
|
||
byte[] hash = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(signStr));
|
||
string sign = System.BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||
// 文档要求大写则 .ToUpperInvariant()
|
||
```
|
||
|
||
**HMAC-SHA1 / HMAC-SHA256 → hex**
|
||
|
||
```csharp
|
||
using (var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(secret))) {
|
||
byte[] hash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(signStr));
|
||
string sign = System.BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||
}
|
||
// HMACSHA1 替换 HMACSHA256;文档要 Base64 则 Convert.ToBase64String(hash)
|
||
```
|
||
|
||
**按键排序后 key+value 拼接(多种开放平台通用)**
|
||
|
||
```csharp
|
||
var parts = new System.Collections.Generic.List<string>();
|
||
// parts.Add("fieldA" + valueA); 排除 sign 字段
|
||
parts.Sort(System.StringComparer.Ordinal);
|
||
var sb = new System.Text.StringBuilder();
|
||
for (int i = 0; i < parts.Count; i++) sb.Append(parts[i]);
|
||
string signStr = sb.ToString(); // 或 prefix + sb + suffix,按文档
|
||
```
|
||
|
||
**secret 包裹式:`secret + params + secret`(1688 等)**
|
||
|
||
```csharp
|
||
string signStr = secret + paramString + secret;
|
||
```
|
||
|
||
**写入 Query / Header / Form(字段名按接口明细)**
|
||
|
||
```csharp
|
||
for (int i = 0; i < obj.QueryFieldList.Count; i++) {
|
||
if (obj.QueryFieldList[i].Name == "sign") {
|
||
obj.QueryFieldList[i].Value = sign;
|
||
break;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. 生成前自检
|
||
|
||
- [ ] 算法、拼接规则、hex 大小写与**用户/文档**一致(不默认某一种)
|
||
- [ ] 读写列表与接口明细 Tab 一致
|
||
- [ ] 签名字段未参与计算
|
||
- [ ] 仅用 `obj`、全限定名、无 `using`
|
||
- [ ] 空密钥有抛错或明确处理
|
||
|
||
---
|
||
|
||
## 示例(仅参考,生成时以用户需求为准)
|
||
|
||
### 示例 A:HMAC-SHA1 + urlPath + 排序 param(阿里国际站 AOP 一类)
|
||
|
||
- 拼接:`urlPath + sort(key+value)`,不含签名字段
|
||
- 输出:Query `_aop_signature`,小写 hex
|
||
- 参数在 **QueryFieldList**;JSON 优先读 `notifyBizEventDTO` 的 Value
|
||
|
||
### 示例 B:MD5 + secret 包裹 + 排序 keyvalue(1688 一类)
|
||
|
||
- 拼接:`appSecret + key1val1key2val2... + appSecret`
|
||
- 输出:Query/Form 的 `sign`,常为大写 hex
|
||
|
||
### 示例 C:HMAC-SHA256 + Header
|
||
|
||
- Body 用 `SerializeObject(OriginalInterfaceMappedInput)` 参与拼接
|
||
- 输出:`HeaderFieldList` 的 `X-Sign` 或 `Authorization`
|
||
|
||
### 示例 D:JSON Body 内写字段
|
||
|
||
- `obj.OriginalInterfaceMappedInput["sign"] = sign;`
|
||
|
||
更多代码模式见 [examples.md](examples.md)。
|
||
|
||
---
|
||
|
||
## 输出要求
|
||
|
||
只输出一个 ```csharp 代码块(Natasha 方法体),不要额外解释。
|
||
|
||
## 禁止事项
|
||
|
||
- 不要用 `HttpClient` 再发请求
|
||
- 不要改 `InParamTreeList` / `OutParamTreeList`
|
||
- 不要用 `TargetInterfaceInput`
|
||
- 不要输出 Python/JavaScript
|
||
- 不要写 `using`;不要用 `context`
|
||
- 不要把 Query/Header 签名写到 `FormFieldList`
|
||
- **不要**在未确认文档时硬编码某一服务商的算法(如默认阿里 HMAC-SHA1)
|
||
- 不要把签名字段放进待签名字符串
|