> 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-unity-sdk/authentication/custom-token-provider.md).

# 编写自定义令牌提供程序

注册一个自定义凭证提供程序，让你的后端为每次连接自动签发短期 Convai 身份验证令牌。

实现 `IConvaiAuthTokenProvider` 当你的项目已经有一个后端或登录层可以签发 Convai 身份验证令牌，并且你希望 SDK 在每次连接时自动调用它。若你的项目处于 Auth Token 模式，并且你希望在不改动每个调用点的连接代码的情况下完成令牌解析，请使用本页。

### 前提条件

* 项目的 `ConvaiSettings` 资源具有 `AuthMode` 设为 `AuthToken`。请参阅 [配置 Auth Token 模式](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/authentication/configure-auth-token-mode.md).
* 一个后端端点或 SDK，它会返回一个短期有效的 Convai 身份验证令牌（即一个 `apiAuthToken`）供已登录玩家使用。

### 实现该接口

`IConvaiAuthTokenProvider` 只有一个方法：

```csharp
public interface IConvaiAuthTokenProvider
{
    Task<AuthTokenResult> GetTokenAsync(CancellationToken cancellationToken);
}
```

SDK 会调用 `GetTokenAsync` 对每一次新的房间连接尝试调用一次。返回 `AuthTokenResult.Succeeded(token, expiresAtUtc)` 成功时，或 `AuthTokenResult.Failed(errorMessage)` 当无法解析令牌时。 `expiresAtUtc` 是可选的。

{% code title="Assets/Scripts/MyAuthTokenProvider.cs" %}

```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
using Convai.Runtime.Core.Configuration;

public sealed class MyAuthTokenProvider : IConvaiAuthTokenProvider
{
    public async Task<AuthTokenResult> GetTokenAsync(CancellationToken cancellationToken)
    {
        try
        {
            string token = await MyBackend.RequestConvaiTokenAsync(cancellationToken);
            return string.IsNullOrWhiteSpace(token)
                ? AuthTokenResult.Failed("我的后端返回了空令牌。")
                : AuthTokenResult.Succeeded(token);
        }
        catch (Exception exception)
        {
            return AuthTokenResult.Failed($"我的后端请求失败（{exception.GetType().Name}）。");
        }
    }
}
```

{% endcode %}

{% hint style="warning" %}
`IConvaiAuthTokenProvider` 实现不得记录或持久化返回的令牌。将其视为仅限单次连接尝试的短期机密。
{% endhint %}

### 在连接前注册提供者

使用以下方式注册提供者： `ConvaiAuthTokenProviderRegistry` 在第一次连接尝试之前，通常在较早的 `Awake`:

```csharp
using Convai.Runtime.Core.Configuration;
using UnityEngine;

public sealed class AuthBootstrap : MonoBehaviour
{
    private MyAuthTokenProvider _provider;

    private void Awake()
    {
        _provider = new MyAuthTokenProvider();
        ConvaiAuthTokenProviderRegistry.Register(_provider);
    }

    private void OnDestroy()
    {
        ConvaiAuthTokenProviderRegistry.Unregister(_provider);
    }
}
```

`ConvaiAuthTokenProviderRegistry.Register` 会替换当前已注册的任意提供者。 `Unregister(provider)` 仅当它仍是当前活动注册时才会移除它； `Unregister()` 无参数的 Unregister() 以及 `Clear()` 都会移除当前活动的提供者。

{% hint style="warning" %}
`ConvaiAuthTokenProviderRegistry` 是一个静态的、进程本地的注册，会在以下情况下自动重置： `RuntimeInitializeLoadType.SubsystemRegistration`。这会在每次域重新加载以及每次进入 Play 模式时运行，因此一次注册的提供者不会保留下来——请在你的引导脚本每次运行时重新注册提供者，而不要假设一次调用就足够。
{% endhint %}

### 在简单情况下使用委托

对于只需要一次异步查找的提供者，请将 lambda 包装在 `DelegateAuthTokenProvider` 而不是编写完整类：

```csharp
using Convai.Runtime.Core.Configuration;

ConvaiAuthTokenProviderRegistry.Register(
    new DelegateAuthTokenProvider(async cancellationToken =>
        await MyBackend.RequestConvaiTokenAsync(cancellationToken)));
```

`DelegateAuthTokenProvider` 包装一个 `Func<CancellationToken, Task<string>>`。如果……则会以 `AuthTokenResult.Failed` 的形式失败，如果委托返回 `null`、空任务或空字符串，因此你的委托只需返回令牌字符串或抛出异常即可。

### 验证设置

进入 Play 模式并连接一个角色。如果提供者解析正确，连接将继续且不会出现与身份验证相关的错误。如果失败，连接会通过正常的连接错误路径显示来自 `AuthTokenResult.Failed` 的消息。

### 下一步

{% content-ref url="/pages/1e83cf2de6c0f33600727e9d53472326fe916861" %}
[使用现有身份验证令牌连接](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/authentication/connect-with-auth-token.md)
{% endcontent-ref %}

{% content-ref url="/pages/fb645a3f7b0858dadf0b26ee09f168a43e9e98b7" %}
[身份验证脚本参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/authentication/scripting-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/2b331d8b6d61de917a4ae462f423b45b693555f4" %}
[身份验证故障排查](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/authentication/troubleshooting.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-unity-sdk/authentication/custom-token-provider.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.
