# 服务令牌和访问令牌支持

> Use Access Tokens and Service Tokens to authenticate requests in Cloud Code modules.

在模块中，`IExecutionContext` 接口提供一个 `AccessToken` 和一个 `ServiceToken`。

| 令牌类型           | 来源                                                            | 数据访问         | 用途                                                                              |
| -------------- | ------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------- |
| `accessToken`  | 由 [Authentication 服务](/authentication/use-anon-sign-in.md)生成。 | 仅限经过身份验证的玩家。 | `AccessToken` 是用于对 Cloud Code 调用进行身份验证的 JWT。您可以将此令牌传递给其他 UGS 服务来访问经过身份验证的玩家的数据。 |
| `serviceToken` | 由 Cloud Code 生成。                                              | 跨玩家数据访问。     | `ServiceToken` 是用于调用其他 UGS 服务并处理跨玩家数据的令牌。                                       |

在调用其他 UGS 服务时，您可以使用这些令牌以玩家身份或 Cloud Code 身份进行身份验证。

请参阅[身份验证](./authentication.md)页面以了解更多信息。

## 概述##overview

请评估您是要以玩家身份还是以受信任的客户端身份进行身份验证。

模块 `IExecutionContext` 接口为您提供一个 `AccessToken` 和一个 `ServiceToken`。

如果模块的目的是仅访问经过身份验证的玩家的数据，则应使用 `AccessToken` 以玩家身份进行身份验证来调用模块终端。这将确保玩家只能访问和处理自己的数据。

如果模块的目的是访问跨玩家数据，则应使用 `ServiceToken` 以 Cloud Code 身份进行身份验证。这将确保模块可以访问和处理跨玩家数据。但是，这为恶意玩家调用模块终端并访问非预期跨玩家数据创造了机会。为防止出现这种情况，应确保模块受到[访问控制](./access-control.md)规则的保护。

要详细了解如何处理跨玩家数据，请参阅[跨玩家数据](./cross-player-data.md)文档。

## 访问令牌支持##access-token-support

访问令牌是 [Authentication 服务](/authentication/use-anon-sign-in.md) ([/authentication/use-anon-sign-in](/authentication/use-anon-sign-in.md)) 生成的 [JWT](https://jwt.io/)。您可以使用访问令牌对玩家进行身份验证。

当经过身份验证的玩家调用 Cloud Code 模块时，他们会将自己的访问令牌作为 `IExecutionContext` 接口的 `AccessToken` 属性传递给该模块。

您可以将访问令牌用于 Cloud Code C# Game SDK。要将访问令牌用于其他 UGS API，您需要在 Authentication 标头中将令牌作为持有者令牌传递。

### 支持的服务##supported-services

要检查哪些服务支持访问令牌，请参阅下表：

| 提供者                      | 支持的服务                                                                            |
| ------------------------ | -------------------------------------------------------------------------------- |
| Cloud Code C# Client SDK | 所有 Cloud Code C# Client SDK 都与其对应的服务 API 支持相同的访问令牌。                              |
| UGS Client API           | 所有支持 Authentication 服务的 UGS 服务。                                                  |
| Cloud Code C# Admin SDK  | 不支持。改用[服务帐户身份验证](./authentication.md#cloud-code-admin-api-basic-authentication)。 |
| UGS Admin API            | 不支持。改用[服务帐户身份验证](./authentication.md#cloud-code-admin-api-basic-authentication)。 |

> **Note:**
>
> **注意**：大多数 UGS 服务都接入了 Authentication 服务，并支持访问令牌。

### 将令牌用于 Cloud Code C# Client SDK##use-tokens-with-cloud-code-c-client-sdks

要将 `AccessToken` 用于 Cloud Code C# Client SDK，您需要从 `IExecutionContext` 接口传递令牌。

以下示例将增加调用该模块的玩家的货币余额：

```csharp
[CloudCodeFunction("IncrementBalance")]
public async Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
{
    ...
    try
    {
    // Increment the balance of the currency for the player calling the module
    var res =  await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.AccessToken,
            ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

    _logger.LogInformation("Incremented currency {currencyId} balance by {amount}", currencyId, 10);
    return res;

    }
    catch (ApiException e)
    {
        _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
        throw new Exception($"Failed to increment {currencyId} balance for playerId {ctx.PlayerId}. Error: {e.Message}");
    }
}

```

### 用于 UGS Client API##use-with-ugs-client-apis

要将 `AccessToken` 用于 UGS Client API，请在 Authentication 标头中将令牌作为持有者令牌传递。

> **Note:**
>
> **注意**：如果要调用的服务提供了 Cloud Code C# SDK，则可以使用该 SDK，而不是直接调用服务 API。如需查看可用 SDK 的列表，请参阅[可用库](../reference/available-libraries)页面。

```csharp
public class Relationships
{
    private readonly RestClient _httpClient;

    public Relationships()
    {
        _httpClient = new RestClient("https://social.services.api.unity.com/v1/relationships");
    }

    public async Task<List<RelationshipsApiResponse?>> GetRelationships(IExecutionContext context)
    {
        var request = new RestRequest()
        {
            // Pass the access token as a bearer token in the header
            Authenticator = new JwtAuthenticator(context.AccessToken)
        };

        ....
    }

}
```

## 服务令牌支持##service-token-support

服务令牌是 Cloud Code 生成的 [JWT](https://jwt.io/)。您可以使用服务令牌以 Cloud Code 身份对服务进行身份验证。这是经过[令牌交换](./authentication.md#cloud-code-client-api-bearer-authentication)过程的服务帐户令牌。

您可以将服务令牌用于 Cloud Code C# Client SDK。要将其用于其他 API，您需要在 Authentication 标头中将其作为持有者令牌传递。

### 支持的服务##supported-services

如需查看支持服务令牌的服务列表，请参阅下表：

| 提供者                      | 支持的服务                                                                                                                                                                                                       |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Cloud Code C# Client SDK | 请参阅[可用库](../reference/available-libraries)以查看可用 SDK 的列表。                                                                                                                                                    |
| UGS Client API           | [Cloud Save][Cloud Save Client API][Economy][Economy Client API][Leaderboards][Leaderboards Client API] [Lobby][Lobby Client API][Player Names][Player Names Client API][Matchmaker][Matchmaker Client API] |
| Cloud Code C# Admin SDK  | 不支持。改用[服务帐户身份验证](./authentication.md#cloud-code-admin-api-basic-authentication)。                                                                                                                            |
| UGS Admin API            | 不支持。改用[服务帐户身份验证](./authentication.md#cloud-code-admin-api-basic-authentication)。                                                                                                                            |

> **Note:**
>
> **注意：** 我们仍在编写 Cloud Code C# Client SDK 的文档。现在，您可以暂时参考 [JavaScript 文档](../../scripts/how-to-guides/unity-services-integration)，其具有类似的结构。此外，请利用集成开发环境的自动补全和智能感知功能。

[Cloud Save Client API]: https://services.docs.unity.com/cloud-save/v1/

[Economy Client API]: https://services.docs.unity.com/economy/v2/

[Leaderboards Client API]: https://services.docs.unity.com/leaderboards/v1/

[Lobby Client API]: https://services.docs.unity.com/lobby/v1/

[Player Names Client API]: https://services.docs.unity.com/player-names/v1/

[Matchmaker Client API]: https://services.docs.unity.com/matchmaker/v2/

### 将令牌用于 Cloud Code C# Client SDK##use-tokens-with-cloud-code-c-client-sdks

要将 `ServiceToken` 用于 Cloud Code C# Client SDK，请从 `IExecutionContext` 接口传递令牌。

以下示例接受一个玩家 ID 并增加该玩家的货币余额：

```csharp
[CloudCodeFunction("IncrementBalance")]
public async Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId, string playerId)
{
    ...
    try
    {
    // Increment the balance of the currency for the player ID passed in, authenticated as Cloud Code
    var res =  await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
            ctx.ProjectId, playerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

    _logger.LogInformation("Incremented currency {currencyId} balance by {amount}", currencyId, 10);
    return res;

    }
    catch (ApiException e)
    {
        _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
        throw new Exception($"Failed to increment {currencyId} balance for playerId {ctx.PlayerId}. Error: {e.Message}");
    }
}
```

### 将令牌用于 UGS Client API##use-tokens-with-ugs-client-apis

要将 `ServiceToken` 用于 UGS Client API，请在 Authentication 标头中将令牌作为持有者令牌传递。

> **Note:**
>
> **注意：** 如果调用的服务提供了 Cloud Code C# SDK，则可以使用该 SDK，而不是直接调用服务 API。如需查看可用 SDK 的列表，请参阅[可用库](../reference/available-libraries)页面。

例如，如果您为 Cloud Save API 定义了一个接口，则可以使用 `ServiceToken` 进行身份验证并处理跨玩家数据。以下示例接受一个玩家 ID 并返回为该玩家存储的所有数据：

```csharp
using System.Net;
using Unity.Services.CloudCode.Core;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Authenticators;

namespace ExampleModule;

public interface ICloudSaveData
{
    public Task<CloudSaveResponse?> GetData(IExecutionContext context, string playerId);
}

public class CloudSaveResponse
{
    public CloudSaveItem[] Results { get; set; }
}

public class CloudSaveItem
{
    public string Key { get; set; }
    public object Value { get; set; }
}

public class CloudSaveData : ICloudSaveData
{
    private readonly RestClient _httpClient;

    public async Task<CloudSaveResponse?> GetData(IExecutionContext context, string playerId)
    {
        var request = new RestRequest($"v1/data/projects/{context.ProjectId}/players/{playerId}/items")
        {
            // Authenticate as Cloud Code to interact with cross-player data
            Authenticator = new JwtAuthenticator(context.ServiceToken)
        };

           // Pass through the analytics user id and Unity installation id to the service.
        if (context.AnalyticsUserId != null)
            request = request.AddHeader("analytics-user-id", context.AnalyticsUserId);
        if (context.UnityInstallationId != null)
            request = request.AddHeader("unity-installation-id", context.UnityInstallationId);

        RestResponse response = await _httpClient.ExecuteGetAsync(request);
        if (response.Content == null)
            throw new Exception("Failed to load data from Cloud Save: Content was null");

        if (response.StatusCode != HttpStatusCode.OK)
            throw new Exception("Failed to load data from Cloud Save: " + response.Content);

        return JsonConvert.DeserializeObject<CloudSaveResponse>(response.Content);
    }
}
```

> **Note:**
>
> **注意：** Cloud Code 提供了一个 Cloud Save C# SDK 来处理 Cloud Save 数据。以上示例演示了如何使用 `ServiceToken` 向其他 UGS 服务进行身份验证。
