# การตรวจสอบสิทธิ์และการลงนาม

คำขอ Weydub API ใช้ส่วนหัว `AppKey` และ `AppSign` โปรดเก็บ `AppSecret` ไว้เฉพาะฝั่งเซิร์ฟเวอร์

## โครงสร้างคำขอ

| รายการ | ค่า |
| --- | --- |
| URL หลัก | `https://api.zhaoli.com` |
| โปรโตคอล | HTTPS |
| เมธอด | `POST` สำหรับการเรียก API ตามที่ระบุไว้ในเอกสาร |
| การเข้ารหัสอักขระ | UTF-8 |
| ชนิดเนื้อหา | `application/json` |
| เนื้อหาคำขอ | JSON ซึ่งซีเรียลไลซ์แบบกระชับเพื่อให้ลายเซ็นมีค่าคงที่ |

## ส่วนหัว

```text
Content-Type: application/json
AppKey: your_app_key
AppSign: computed_signature
```

จะไม่มีการส่ง `AppSecret` เป็นส่วนหัวหรือฟิลด์ในเนื้อหาคำขอ โดยจะใช้เฉพาะบนเซิร์ฟเวอร์ของคุณเพื่อคำนวณ `AppSign` เท่านั้น

## สูตรการคำนวณลายเซ็น

```text
AppSign = md5(md5(request_body) + AppSecret)
```

ต้องคำนวณลายเซ็นจากเนื้อหา JSON ที่ส่งผ่านเครือข่ายจริงแบบตรงกันทุกประการ เพื่อให้ลายเซ็นมีค่าคงที่ ให้ซีเรียลไลซ์ JSON โดยไม่มีช่องว่างเพิ่มเติม

หากปลายทางอนุญาตให้ใช้เนื้อหาคำขอว่าง ให้ลงนามไบต์ชุดเดียวกันทุกประการกับที่คุณส่ง สำหรับการผสานรวมส่วนใหญ่ ควรส่ง `{}` และลงนาม `{}` สำหรับการเรียกที่ไม่มีเนื้อหาคำขอ

## ปลายทางที่ไม่ต้องลงนาม

ปลายทาง enum ไม่ต้องลงนาม:

```text
POST /v-w-c/enum/query2
```

ใช้ปลายทางนี้เพื่อดึงค่า enum ภาษา/สถานะแบบไดนามิก เช่น `sourceLang`, `Lang`, `ProcessStatus` และ `ImageTaskStatus`

## ตัวช่วยลงนามสำหรับ Python

```python
import hashlib
import json


def signed_body_and_headers(payload: dict, app_key: str, app_secret: str):
    body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
    body_md5 = hashlib.md5(body.encode("utf-8")).hexdigest()
    app_sign = hashlib.md5((body_md5 + app_secret).encode("utf-8")).hexdigest()
    return body, {
        "Content-Type": "application/json",
        "AppKey": app_key,
        "AppSign": app_sign,
    }
```

## ตัวช่วยลงนามสำหรับ Node

```js
import crypto from "node:crypto";

export function signedBodyAndHeaders(payload, appKey, appSecret) {
  const body = JSON.stringify(payload);
  const bodyMd5 = crypto.createHash("md5").update(body).digest("hex");
  const appSign = crypto.createHash("md5").update(bodyMd5 + appSecret).digest("hex");
  return {
    body,
    headers: {
      "Content-Type": "application/json",
      AppKey: appKey,
      AppSign: appSign,
    },
  };
}
```

## รูปแบบ cURL

ใช้แบ็กเอนด์ของคุณคำนวณ `AppSign` แล้วส่งเนื้อหาคำขอชุดเดียวกันทุกประการ:

```bash
curl -X POST "https://api.zhaoli.com/v-w-c/gateway/ve/work/status" \
  -H "Content-Type: application/json" \
  -H "AppKey: $WEYDUB_APP_KEY" \
  -H "AppSign: $WEYDUB_APP_SIGN" \
  --data '{"idWorks":[488026661]}'
```

## การลงนามคอลแบ็ก

เมื่อ Weydub ส่งคอลแบ็ก คอลแบ็กจะมีข้อมูลต่อไปนี้:

```text
Callback-Sign: computed_callback_signature
```

ตรวจสอบคอลแบ็กด้วยสูตรเดียวกัน โดยใช้เนื้อหาดิบของคำขอคอลแบ็ก:

```text
expected = md5(md5(raw_callback_body) + AppSecret)
```

เปรียบเทียบ `expected` กับ `Callback-Sign` และปฏิเสธหรือกักกันเพย์โหลดคอลแบ็กที่ไม่ผ่านการตรวจสอบ

## ข้อผิดพลาดที่พบบ่อย

- ลงนาม JSON ที่จัดรูปแบบให้อ่านง่าย แต่ส่ง JSON แบบกระชับ
- เปลี่ยนแปลงเพย์โหลดหลังจากลงนามแล้ว
- ใช้การเอสเคปสตริงต่างกันระหว่างการลงนามกับการส่ง
- ลงนามออบเจ็กต์ในหน่วยความจำแทนชุดไบต์ขั้นสุดท้ายที่ส่งผ่าน HTTP จริง
- ลืมว่า `extraOptions`, `wyVoiceParam`, `videoInpaintMasks`, `downloadInfo` และ `result` สำหรับการทำซ้ำ อาจจำเป็นต้องคงไว้เป็นสตริง JSON แบบกระชับภายในเนื้อหาคำขอ JSON ชั้นนอก
- ใส่ข้อมูลรับรองไว้ในโค้ดฟรอนต์เอนด์
- แชร์ `AppSecret` กับส่วนขยายเบราว์เซอร์ แอปฝั่งไคลเอนต์ ภาพหน้าจอ บันทึก หรือพรอมป์สาธารณะ

## กฎสำหรับเอเจนต์

- อ่านข้อมูลรับรองจากตัวแปรสภาพแวดล้อมหรือระบบจัดการข้อมูลลับ
- ห้ามแสดง `AppSecret` กลับออกมาโดยเด็ดขาด
- ห้ามเขียนข้อมูลรับรองลงในไฟล์ตัวอย่างที่สร้างขึ้นโดยเด็ดขาด
- เมื่อสร้างตัวอย่างที่เรียกใช้ได้ ให้ใช้ตัวยึดตำแหน่งหรือตัวแปรสภาพแวดล้อม
- เมื่อแก้ไขข้อผิดพลาดเกี่ยวกับลายเซ็น ให้เปรียบเทียบไบต์ของเนื้อหาคำขอและค่าแฮชของเนื้อหาคำขอที่ไม่ใช่ข้อมูลลับ โดยไม่พิมพ์ข้อมูลลับออกมา
- ตรวจสอบ `Callback-Sign` ในตัวจัดการเว็บฮุก
