> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/advanced-topics/personal-access-token.md).

# 使用个人访问令牌

在后端生成一个短期令牌并将其传递给 Unreal 插件，这样生产构建就不会打包真实 API 密钥。

默认情况下，Convai Unreal Engine 插件会将您的 API 密钥存储在 `UConvaiSettings.API_Key` — 在 UE 5.2+ 中通过 Convai 编辑器窗口，或在 `Config/DefaultEngine.ini` 在 UE 5.0 和 5.1 中。该流程适用于编辑器测试和早期原型。在 **打包应用**中，任何检查该构建的人都可以读取已存储的 API 密钥，并将其用于您的 Convai 账户。

**个人访问令牌（PAT）** 可避免这种暴露。您的真实 API 密钥保留在 **后端** — 您控制的服务器端应用程序（Node.js、Python、.NET、AWS Lambda 等）。后端会调用 Convai 以生成一个短期有效的 `apiAuthToken` （有效期约一小时），并在运行时将其返回给您的 Unreal 项目。会话开始时，插件会发送该令牌。如果令牌被截获，它会在一小时内过期。

{% hint style="info" %}
**我应该使用这个吗？** 使用常规 [配置你的 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/configure-your-api-key.md) 流程用于本地编辑器测试。当您发布打包构建且不能嵌入真实 API 密钥时，请使用个人访问令牌。
{% endhint %}

### 前置条件

* 已安装 Convai Unreal Engine 插件，并且您已使用普通 API 密钥完成一次成功的对话测试。请参阅 [配置你的 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/configure-your-api-key.md) 和 [添加你的第一个 Convai 角色](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/add-your-first-convai-character.md).
* 您控制的后端，可将真实的 Convai API 密钥作为服务器端机密存储。
* 从后端到 `https://api.convai.com`.

### 令牌流程如何工作

PAT 流程中有三个角色参与：

| 角色            | 它持有什么              | 它的作用                                |
| ------------- | ------------------ | ----------------------------------- |
| **后端**        | 真实的 Convai API 密钥  | 调用 Convai 令牌端点；绝不会将密钥暴露给 Unreal 构建。 |
| **Convai**    | 您的账户和角色            | 返回一个短期有效的 `apiAuthToken`.           |
| **Unreal 项目** | 该 `apiAuthToken` 仅 | 在会话开始前将令牌设置到插件中。                    |

```mermaid
graph TD
    Backend["您的后端\n（持有真实 API 密钥）"]
    ConvaiAPI["Convai\nPOST /user/connect"]
    UnrealApp["Unreal 项目\n（接收 apiAuthToken）"]
    Session["Convai 会话\n（WebRTC）"]

    Backend -->|"CONVAI-API-KEY header"| ConvaiAPI
    ConvaiAPI -->|"apiAuthToken (~1 hour)"| Backend
    Backend -->|"在运行时交付"| UnrealApp
    UnrealApp -->|"在开始会话前设置 SetAuthToken"| Session
```

Unreal 项目必须 **绝不** 调用 `https://api.convai.com/user/connect` 直接访问。该端点需要真实的 API 密钥——将其嵌入客户端会使 PAT 的目的失效。

### 在后端生成令牌

所有令牌端点都指向 `https://api.convai.com` 并且需要您真实的 API 密钥位于 `CONVAI-API-KEY` 请求头中。请仅从您的后端发起这些调用。

#### 生成令牌

```http
POST https://api.convai.com/user/connect
```

| 请求头              | 值                  |
| ---------------- | ------------------ |
| `Content-Type`   | `application/json` |
| `CONVAI-API-KEY` | 您的 Convai API 密钥   |

**请求体：** `{}`

**响应：**

```json
{
  "apiAuthToken": "eyJhbGciOi...",
  "expirationTime": "2024-01-15T14:30:00Z"
}
```

| 字段               | 说明                      |
| ---------------- | ----------------------- |
| `apiAuthToken`   | 要交付给 Unreal 项目的短期令牌。    |
| `expirationTime` | 过期的 UTC 时间戳——大约在生成后一小时。 |

在当前令牌仍然有效时，您可以生成一个新令牌。生成新令牌不会使前一个令牌失效。

**后端示例（Python）：**

```python
import requests

def get_api_auth_token(api_key: str) -> str:
    url = "https://api.convai.com/user/connect"
    headers = {
        "CONVAI-API-KEY": api_key,
        "Content-Type": "application/json",
    }
    response = requests.post(url, headers=headers, json={})
    response.raise_for_status()
    return response.json()["apiAuthToken"]
```

#### 延长令牌

```http
POST https://api.convai.com/user/extend-token
```

请求头：与生成时相同。

```json
{
  "apiAuthToken": "eyJhbGciOi..."
}
```

重置现有令牌的过期计时，但不会使其失效。

#### 撤销令牌

```http
POST https://api.convai.com/user/revoke-token
```

请求头：与生成时相同。

```json
{
  "apiAuthToken": "eyJhbGciOi..."
}
```

立即使令牌失效。在注销时或令牌不再需要时调用此接口。最好通过您的后端代理撤销操作，以便真实的 API 密钥绝不会随客户端一起发布。

### 在 Unreal Engine 中使用令牌

插件通过以下方式读取凭据 `UConvaiUtils::GetAuthHeaderAndKey()`。当 `UConvaiSettings.API_Key` 是 **非空**时，插件会使用 API 密钥并带上 `CONVAI-API-KEY` 请求头。当 `API_Key` 为空，并且 `AuthToken` 已设置时，插件会改为使用该令牌并带上 `API-AUTH-TOKEN` 请求头。

生产环境 PAT 流程需要 **两个独立步骤**：从磁盘上的项目中移除 API 密钥 **在打包之前**，然后在运行时设置一个新的令牌 **之前** `开始会话`。跳过打包步骤会导致 `API_Key` 即使您在编辑器中于运行时清除了它，它仍会留在已发布的构建中。

| 组件                        | 当自动初始化运行时                     | 何时设置令牌                                               |
| ------------------------- | ----------------------------- | ---------------------------------------------------- |
| `UConvaiChatbotComponent` | `BeginPlay` 当 **自动初始化会话** 已启用 | 在该组件的 `BeginPlay` 完成之前——例如从 `GameMode` 或更早启动的 Actor。 |
| `UConvaiPlayerComponent`  | 当全局连接达到 `已连接`                 | 在子系统报告 `已连接` 之前——不一定在 `BeginPlay`.                   |

### 在打包前清除 API 密钥

当您通过 Convai 编辑器窗口登录时，插件会写入 `API_Key` 为 `Config/DefaultEngine.ini`。Unreal Engine **会在打包构建中包含该文件**。如果 `API_Key` 在打包时仍处于设置状态，那么真实密钥就会随构建一起发布——运行时的 PAT 无法在事后修复这种暴露。

完成此步骤 **之前** 在创建正式发布构建之前。请使用以下方法之一。

{% tabs %}
{% tab title="退出登录（UE 5.2+）" %}
{% stepper %}
{% step %}

#### 打开账户菜单

在 Convai 编辑器窗口中，点击右上角的账户控件。
{% endstep %}

{% step %}

#### 退出登录

选择 **退出登录**。插件会清除 `API_Key` 和 `AuthToken` 来自 `Config/DefaultEngine.ini`.
{% endstep %}

{% step %}

#### 确认文件已清空

打开 `Config/DefaultEngine.ini` 并确认 `API_Key` 在下方的行 `[/Script/Convai.ConvaiSettings]` 为空或已移除。 **API 密钥** 中的字段 **编辑 > 项目设置 > 插件 > Convai** 也应为空。
{% endstep %}
{% endstepper %}
{% endtab %}

{% tab title="编辑 DefaultEngine.ini（所有 UE 版本）" %}
{% stepper %}
{% step %}

#### 关闭编辑器

在编辑文件之前先关闭 Unreal Editor，以免在关闭时覆盖您的更改。
{% endstep %}

{% step %}

#### 清除 API\_Key 和 AuthToken

打开 `Config/DefaultEngine.ini` 在您的项目文件夹中。在 `[/Script/Convai.ConvaiSettings]`下，删除 `API_Key` 该行或将其设置为空值。也请以同样方式清除 `AuthToken` 如果存在的话。

{% code title="Config/DefaultEngine.ini" %}

```ini
[/Script/Convai.ConvaiSettings]
API_Key=
AuthToken=
```

{% endcode %}
{% endstep %}

{% step %}

#### 在打包前确认

重新启动编辑器并打开 **编辑 > 项目设置 > 插件 > Convai**。确认 **API 密钥** 为空，然后创建您的打包构建。
{% endstep %}
{% endstepper %}
{% endtab %}
{% endtabs %}

参见 [移除或清除 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/configure-your-api-key.md#remove-or-clear-the-api-key) 以查看本地凭据存储的完整参考。

### 在运行时设置令牌

在打包构建中不包含已存储 API 密钥后，获取一个新的 `apiAuthToken` ，在每次启动时从您的后端获取并在之前应用它 `开始会话`.

{% tabs %}
{% tab title="蓝图" %}
{% stepper %}
{% step %}

#### 从您的后端获取令牌

当玩家登录时——或在应用启动时——调用您的后端端点。使用您自己的应用会话对该请求进行身份验证（例如来自登录系统的 bearer 令牌）。您的后端返回 `apiAuthToken` 字符串。

不要调用 `https://api.convai.com/user/connect` ，无论是从 Blueprint 还是从任何客户端图中。
{% endstep %}

{% step %}

#### 清除任何内存中的 API 密钥

在同一个 Blueprint 图中，调用 **设置 API 密钥** (`Convai|Settings`）并传入空字符串。这会清除运行时仍加载在内存中的任何密钥。

您还必须完成 [在打包前清除 API 密钥](#clear-the-api-key-before-packaging) 以便 `API_Key` 不会出现在已发布的 `DefaultEngine.ini`.
{% endstep %}

{% step %}

#### 设置身份验证令牌

调用 **设置 Auth Token** (`Convai|Settings`）。将 `apiAuthToken` 来自后端响应的值连接到 **身份验证令牌** 输入引脚。
{% endstep %}

{% step %}

#### 开始或重新连接会话

如果 **自动初始化会话** 已启用时，请在自动初始化触发之前设置令牌——在 `BeginPlay` 针对聊天机器人组件，或者在全局连接达到 `已连接` 针对玩家组件。若时机不确定，请禁用 **自动初始化会话** 并调用 **开始会话** 在令牌设置后手动执行。

参见 [会话生命周期](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/session-lifecycle.md) 用于手动会话控制。
{% endstep %}
{% endstepper %}
{% endtab %}

{% tab title="C++" %}
包含 `ConvaiUtils.h` 并在 Convai 会话开始前设置令牌。调用 `UConvaiUtils::SetAPI_Key(TEXT(""))` 以清除运行时内存中加载的任何密钥。

完成 [在打包前清除 API 密钥](#clear-the-api-key-before-packaging) 先执行，以便已发布的 `DefaultEngine.ini` 不包含 `API_Key`.

{% code title="Source/MyProject/Private/PatSessionBootstrap.cpp" %}

```cpp
#include "ConvaiUtils.h"

void ApplyPersonalAccessToken(const FString& ApiAuthToken)
{
    // API_Key 非空时优先使用——在仅使用 PAT 的生产构建中请将其清空。
    UConvaiUtils::SetAPI_Key(TEXT(""));
    UConvaiUtils::SetAuthToken(ApiAuthToken);
}
```

{% endcode %}

调用 `ApplyPersonalAccessToken` 在后端 HTTP 请求完成后、以及在……之前 `StartSession` 在聊天机器人或玩家组件上。当 **自动初始化会话** 已启用时，在早期启动阶段应用令牌——从 `GameMode` 或玩家控制器 `BeginPlay` 针对聊天机器人，并且在全局连接达到 `已连接` 针对玩家组件。
{% endtab %}
{% endtabs %}

{% hint style="danger" %}
切勿调用 `https://api.convai.com/user/connect` 来自 Unreal 项目——这会要求客户端构建中包含真实 API 密钥。不要将 `apiAuthToken` 写入打包构建的磁盘中；请在每次启动时从您的后端获取新令牌。优先使用 `UConvaiUtils::SetAuthToken()` 而不是 `UConvaiSettings::SetAuthToken()` 用于短期运行时令牌。
{% endhint %}

### 选择 Blueprint 或 C++

两种路径都会写入同一个 `UConvaiSettings.AuthToken` 字段。令牌设置后，插件行为相同。

| 项目类型                  | 推荐路径                                                                             |
| --------------------- | -------------------------------------------------------------------------------- |
| 仅 Blueprint           | **设置 Auth Token** 和 **设置 API 密钥** 位于 \`Convai 下的节点                               |
| C++ 或混合 C++/Blueprint | `UConvaiUtils::SetAuthToken()` 和 `UConvaiUtils::SetAPI_Key()` 来自 `ConvaiUtils.h` |

使用与你的登录或会话启动逻辑所在位置相匹配的路径即可。仅 Blueprint 项目通常不需要使用 C++ 来进行 PAT 设置。

### 令牌过期与会话

一旦 Convai WebRTC 会话开始，在该会话期间不会重新检查令牌。会话中途过期的令牌不会断开玩家连接。PAT 在连接时即被使用。

| 场景               | 行为                               |
| ---------------- | -------------------------------- |
| 令牌在之前过期 **开始会话** | 连接失败——从您的后端获取新令牌并重试。             |
| 令牌在活动会话期间过期      | 会话会继续，直到自然结束。                    |
| 令牌过期后应用重启        | 在启动时获取一个新令牌——不要在不同启动之间重复使用缓存的令牌。 |

您的后端可以调用 `/user/extend-token` ，或者在玩家开始新会话之前生成一个新令牌。

### 使用示例：企业培训自助终端

企业安全培训自助终端通过 LMS 后端对每位学习者进行身份验证。当学习者登录时，后端会连同 LMS 会话数据一起返回一个 Convai PAT。Unreal 项目会清除任何嵌入的 API 密钥，设置令牌，并开始对话。

```cpp
// PatKioskBootstrap.cpp — 伪代码模式
void APatKioskBootstrap::OnLearnerSignedIn(const FString& LmsSessionBearer)
{
    Backend->FetchConvaiToken(LmsSessionBearer, [this](const FString& ApiAuthToken)
    {
        UConvaiUtils::SetAPI_Key(TEXT(""));
        UConvaiUtils::SetAuthToken(ApiAuthToken);
        // 在令牌应用后，在玩家/聊天机器人组件上调用 StartSession。
    });
}
```

在注销时，后端可以调用 `/user/revoke-token` 以便 PAT 不能在共享设备上被重复使用。

### 故障排除

| 症状                      | 可能原因                                                       | 修复方法                                                                                                                                                                                                                                                     |
| ----------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 连接立即失败                  | `apiAuthToken` 为空——后端获取失败                                  | 请验证您的后端 URL、身份验证请求头，以及后端是否返回非空令牌字符串。                                                                                                                                                                                                                     |
| `401` 连接时身份验证错误         | 令牌在之前过期或已撤销 **开始会话**                                       | 请在开始会话之前立即获取新令牌。                                                                                                                                                                                                                                         |
| PAT 被忽略；仍在使用 API 密钥     | `UConvaiSettings.API_Key` 仍然填充在 `Config/DefaultEngine.ini` | 从 Convai 编辑器窗口退出登录，调用 **设置 API 密钥** 并在运行时传入空字符串，或者清除 `API_Key` 在 `Config/DefaultEngine.ini` 在打包前。请参见 [配置你的 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/configure-your-api-key.md#remove-or-clear-the-api-key). |
| 令牌在编辑器中可用，但在打包构建中失败     | 打包构建中仍包含已存储的 API 密钥，或者启动时未获取 PAT                           | 确认运行时令牌获取在自动初始化之前完成；从正式发布配置中清除嵌入的密钥。                                                                                                                                                                                                                     |
| `apiAuthToken` 在后端响应中为空 | 缺少 `CONVAI-API-KEY` 请求头，或者后端调用中的请求体格式错误                    | 请确保请求体为 `{}` 且请求头存在。记录原始后端响应。                                                                                                                                                                                                                            |

### 下一步

{% content-ref url="/pages/d6af0b14fc209017d2d18543ad38076bb0efe8f6" %}
[配置你的 API 密钥](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/getting-started/configure-your-api-key.md)
{% endcontent-ref %}

{% content-ref url="/pages/a8878427b216a80d6b385f1a342c440aa9b398c9" %}
[会话生命周期](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/core-concepts/session-lifecycle.md)
{% endcontent-ref %}

{% content-ref url="/pages/54960e661fc090cc4ab31a059146f22c63a84ad3" %}
[Convai 工具函数](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/blueprint-reference/convai-utility-functions.md)
{% endcontent-ref %}

{% content-ref url="/pages/f1b3d71c37ea498f3d6d84fdf60594d3020ae6bf" %}
[连接和 API 密钥问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/troubleshooting/connection-and-api-key-issues.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unreal-engine-plugin/advanced-topics/personal-access-token.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
