# Xác thực và ký

Các yêu cầu API của Weydub sử dụng các tiêu đề `AppKey` và `AppSign`. Chỉ lưu giữ `AppSecret` ở phía máy chủ.

## Cấu trúc yêu cầu

| Mục | Giá trị |
| --- | --- |
| URL cơ sở | `https://api.zhaoli.com` |
| Giao thức | HTTPS |
| Phương thức | `POST` cho các lệnh gọi API được ghi trong tài liệu |
| Mã hóa ký tự | UTF-8 |
| Loại nội dung | `application/json` |
| Phần thân yêu cầu | JSON, được tuần tự hóa ở dạng thu gọn để chữ ký ổn định |

## Các tiêu đề

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

`AppSecret` không bao giờ được gửi dưới dạng tiêu đề hoặc trường trong phần thân. Giá trị này chỉ được sử dụng trên máy chủ của bạn để tính `AppSign`.

## Công thức tính chữ ký

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

Chữ ký phải được tính từ đúng phần thân JSON được gửi qua mạng. Để chữ ký ổn định, hãy tuần tự hóa JSON mà không có khoảng trắng thừa.

Nếu một điểm cuối cho phép phần thân trống, hãy ký đúng các byte mà bạn gửi. Trong hầu hết trường hợp tích hợp, đối với các lệnh gọi không có phần thân, nên gửi `{}` và ký `{}`.

## Điểm cuối không yêu cầu ký

Điểm cuối enum không yêu cầu ký:

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

Sử dụng điểm cuối này để lấy các enum động về ngôn ngữ/trạng thái, chẳng hạn như `sourceLang`, `Lang`, `ProcessStatus` và `ImageTaskStatus`.

## Hàm hỗ trợ ký bằng 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,
    }
```

## Hàm hỗ trợ ký bằng 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,
    },
  };
}
```

## Mẫu cURL

Sử dụng backend của bạn để tính `AppSign`, sau đó gửi đúng phần thân đó:

```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]}'
```

## Ký lệnh gọi lại

Khi Weydub gửi một lệnh gọi lại, lệnh gọi đó bao gồm:

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

Xác minh các lệnh gọi lại bằng cùng một công thức, sử dụng phần thân thô của yêu cầu gọi lại:

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

So sánh `expected` với `Callback-Sign`. Từ chối hoặc cách ly dữ liệu của lệnh gọi lại nếu xác minh không thành công.

## Các lỗi thường gặp

- Ký JSON được định dạng để dễ đọc nhưng lại gửi JSON ở dạng thu gọn.
- Thay đổi nội dung dữ liệu sau khi ký.
- Sử dụng cách thoát chuỗi khác nhau khi ký và khi gửi.
- Ký một đối tượng trong bộ nhớ thay vì dãy byte cuối cùng được gửi qua HTTP.
- Quên rằng `extraOptions`, `wyVoiceParam`, `videoInpaintMasks`, `downloadInfo` và `result` của thao tác làm lại có thể cần được giữ nguyên dưới dạng các chuỗi JSON thu gọn trong phần thân JSON bên ngoài.
- Đưa thông tin xác thực vào mã frontend.
- Chia sẻ `AppSecret` với các tiện ích mở rộng trình duyệt, ứng dụng phía máy khách, ảnh chụp màn hình, nhật ký hoặc lời nhắc công khai.

## Quy tắc dành cho tác nhân

- Đọc thông tin xác thực từ các biến môi trường hoặc trình quản lý thông tin bí mật.
- Không bao giờ xuất lại `AppSecret`.
- Không bao giờ ghi thông tin xác thực vào các tệp mẫu được tạo.
- Khi tạo các ví dụ có thể chạy được, hãy sử dụng các giá trị giữ chỗ hoặc biến môi trường.
- Khi gỡ lỗi chữ ký, hãy so sánh các byte của phần thân và các giá trị băm không bí mật của phần thân mà không in ra thông tin bí mật.
- Trong các trình xử lý webhook, hãy xác minh `Callback-Sign`.
