# 身份验证

> 了解各 Kanorio API 接受的凭证类型、权限计算方式，以及如何安全地轮替与撤销令牌。

> Markdown version of https://kanorio.com/zh-CN/developers/authentication. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp
>
> Translated from the English original: https://kanorio.com/en/developers/authentication.md

每个 Kanorio API 均针对不同的调用者构建，并各自接受专属凭证。请通过确认调用者身份来选择对应的凭证。

| 令牌 | 前缀 | 身份 | 适用范围 | 用途 |
|---|---|---|---|---|
| 个人访问令牌 | `knr_pat_` | 您本人，受限于您选择的网站与权限 | Management API, MCP | 您的脚本、CLI、需要密钥的编程辅助工具 |
| 服务账户令牌 | `knr_sa_` | 网站本身，非特定个人 | Management API, MCP | CI、调度器以及在人员离职后仍需持续运行的合作伙伴后端 |
| OAuth 访问令牌 | `knr_at_` | 您本人，通过您授权的应用程序 | 仅限 MCP | 内置连接器的辅助工具，例如 Claude 或 ChatGPT |
| 预览令牌 | `knr_pv_` | 单站草稿的只读访问权限 | Content Delivery API | 您自建前端的草稿模式 |
| 顾客令牌 | `knr_cat_` | 单站的单名登录顾客 | Customer API, 受限的 Content Delivery API 读取 | 您前端的登录、购买内容与订单 |

Content Delivery API 对于已发布的内容无需任何凭证。

## Management API

在每次请求 `https://app.kanorio.com/api/v1` 时，请将令牌作为 Bearer 凭证发送。

```bash
curl https://app.kanorio.com/api/v1/sites \
  -H "Authorization: Bearer knr_pat_..."
```

### 个人访问令牌

请在 [账户设置 › API 访问](https://app.kanorio.com/account/api-access) 中创建令牌。创建时您需要选择：

- **网站。** 指定网站，或包含您日后创建的所有网站。创建新网站需要“所有网站”权限。
- **权限。** 选择预设集（只读、编辑内容、完全访问）或个别权限。
- **过期时间。** 令牌皆会过期。过期前您会收到电子邮件与收件箱通知。

令牌在网站上的有效权限，为该令牌允许的范围与您在该网站角色权限的交集。即使是完全访问令牌，也无法编辑您仅具备查看者角色的网站，且仅有网站所有者可以取消发布。

无论选择何种预设集，某些权限永远不会授权给令牌，包括发送或排程简报、导出数据、退款、删除联系人，以及管理成员或账务。代理人可以草拟简报，但必须由人员从后台发送。

### 服务账户

服务账户属于网站，而非个人。即使创建该账户的人员离开团队，它仍能持续运作；撤销服务账户将同时撤销其发出的所有令牌。

1. 打开 [网站设置 › 开发者](https://app.kanorio.com/settings/developer) 并新增服务账户。您仅能授予您自身拥有的权限。
2. 打开该账户并发出令牌。请以其用途命名令牌，例如“GitHub Actions”。`knr_sa_` 值仅会显示一次。

服务账户仅能在其所属网站内运作。账户层级的操作（例如创建网站或列出您所有的网站）会返回 `403 FORBIDDEN`。在 [OpenAPI 文档](https://app.kanorio.com/api/v1/openapi.json) 中的每个操作皆列出了其接受的调用者类型（于 `x-kanorio-principals` 字段）；包含 `SERVICE_ACCOUNT` 的操作才接受服务账户令牌。

缩减服务账户的权限会立即缩减其现有令牌的权限。扩大权限则仅适用于后续发出的令牌。

### 范围

[Management API 参考](https://kanorio.com/en/developers/management-api) 中的每个操作皆显示了其所需的权限。OpenAPI 文档中标记了相同的 `x-kanorio-required-scope` 值。若令牌缺少该范围，将会收到 `403 FORBIDDEN`。请调用 `GET /whoami` 以查看当前令牌的权限。

## MCP

MCP 服务器位于 `https://app.kanorio.com/api/mcp`，它接受相同的个人访问令牌与服务账户令牌，以及 OAuth 2.1 访问令牌。具备内置连接器的助手会自动发现授权服务器，并要求您在浏览器中批准访问。OAuth 访问令牌绑定于 MCP 服务器，REST 端点将会拒绝此类令牌。请参阅 [MCP](https://kanorio.com/zh-CN/developers/mcp)。

## Content Delivery API

已发布的内容为公开且经过边缘缓存，因此浏览器可直接调用。

- **来自其他来源的浏览器调用**，需将该来源加入 [网站设置 › 开发者](https://app.kanorio.com/settings/developer) 下的 **允许的来源**。任何端口上的 `localhost` 与 `127.0.0.1` 永远被允许。CORS 控制浏览器可读取的内容。这并非授权边界，且未经预览令牌，草稿内容绝不会被提供。
- **草稿预览。** 在相同的设置页面中，或使用 `POST /sites/{id}/preview-tokens` 创建 `knr_pv_` 预览令牌。请从您的服务器以 `X-Kanorio-Preview: knr_pv_...` 标头发送。预览响应会绕过缓存且不会被存储。

## Customer API

客户无需密码即可登录。网站所有者可在 **网站设置 › 客户账户** 中选择启用的方法；网站文档的 `customerAccess.methods` 会依显示顺序列出已启用的方法。每种方法最终都会产生相同的 `knr_cat_` 会话令牌。

- **电子邮件验证码** (`email_code`，默认开启) 与 **魔法链接** (`email_link`)：使用电子邮件地址调用 `POST /api/v1/customer/auth/challenge` 即可发送验证码。首先从 `GET /api/v1/customer/auth/protection` 获取机器人检查：若使用内置检查 (`provider: "kanorio"`)，请使用 `@kanorio/sdk` 中的 `solveProtectionChallenge` 解决并随请求发送字段；若使用所有者的 Turnstile、reCAPTCHA 或 hCaptcha 密钥，请使用 `siteKey` 与 `action` 渲染该小工具，并将其令牌作为 `captchaToken` 发送。接着使用 `{ "method": "code", "email", "code" }` 或 `{ "method": "link", "token" }` 调用 `POST /api/v1/customer/auth/verify`。
- **Google** (`google`)：使用 `{ "method": "google", "baseUrl": <您的页面来源> }` 调用 `POST /api/v1/customer/auth/oauth/start`，将会返回提供商 URL；请将浏览器重定向至该处。Kanorio 会托管同意画面，并将浏览器导回带有 `?handoff=` 的 `baseUrl`。请在 60 秒内进行交换：使用 `{ "method": "handoff", "token" }` 调用 `POST /api/v1/customer/auth/verify`。若 Google 账户的电子邮件未经验证，客户将改为收到电子邮件验证码，并被导向至带有 `?email=&verify=1` 的页面。
- **通行密钥** (`passkey`)：调用 `POST /api/v1/customer/auth/passkey/options`，使用选项执行 `navigator.credentials.get()`，接着使用断言与 `challengeId` 调用 `POST /api/v1/customer/auth/passkey/verify`。已登录的客户可在 `/api/v1/customer/passkeys` 管理其通行密钥。通行密钥绑定于网站的主域名，因此验证程序必须在该来源上执行。

请在您的登录 UI 中处理来自 `POST /api/v1/customer/auth/challenge` 的这些响应：

| 代码 | 处理方式 |
|---|---|
| `429 RATE_LIMITED` | 等待 `retryAfter` 秒后，让顾客再次尝试 |
| `403 BOT_PROTECTION_FAILED` | 获取新的挑战（或重置小工具）并重新发送 |
| `503 SERVICE_UNAVAILABLE` | 登录功能暂时不可用；显示重试选项 |
| `503 SHARED_SENDER_PAUSED` | 此网站的电子邮件登录功能暂时暂停；请提供通行密钥 (Passkeys) 或 Google 登录，或请顾客稍后再试 |

`200` 响应绝不会透露电子邮件是否已发送。Kanorio 会根据网站的登录流量调整机器人检查：来自 `/auth/protection` 的挑战可能会要求显示小工具 (`visible: true`) 或更困难的内置谜题，因此请务必根据您获取的挑战进行渲染，而非假设隐形流程。

在调用 Customer API 与受限的 Content Delivery API 读取时，请将令牌作为 `Authorization: Bearer knr_cat_...` 发送。

客户令牌仅代表该网站上的该名客户。它无法读取其他人的数据或调用 Management API。[`<kanorio-login>`](https://kanorio.com/zh-CN/developers/elements) 元素会为您执行此流程。

## 轮替与撤销

- **轮替**：从个人访问令牌的菜单中进行轮替。Kanorio 会发出一个具有相同设置的新令牌，并让旧令牌在您选择的宽限期内（无、一小时或一天）继续运作。若怀疑令牌泄露，请选择“无”。
- **撤销**：撤销令牌以立即停止其运作。下一次使用该令牌的请求将会收到 `401 UNAUTHORIZED`。已完成的工作不会被回滚。
- 使用任何令牌执行的活动，都会出现在网站的活动日志中，并归类于该令牌所有者或服务账户名称下。

## 确保令牌安全

- 将令牌存储在服务器的环境变量或秘密管理服务中。切勿在令牌前加上 `NEXT_PUBLIC_` 或将其封装在移动应用中。
- 切勿将令牌粘贴入 AI 对话中。真正的工具会从配置文件中读取令牌。
- 每个工具使用一个令牌，每个集成使用一个服务账户，以便您能精确撤销单个令牌。
- 给予每个令牌最窄的网站与权限范围。
