# 访问控制

> Implement authorization to protect player data and game resources.

Unity Gaming Services（Unity 游戏服务）(UGS) 的访问控制功能可以保护 UGS 中的游戏状态和逻辑免受作弊者和攻击者的侵害。访问控制（也称为 API 授权）可以让您控制谁有权访问、修改或删除游戏数据和资源，以保护游戏免受未经授权的访问，因此非常重要。

UGS 的 API 授权是确定用户在经过身份验证后可以执行哪些操作的过程。身份验证可以验证用户的真实身份。身份验证和授权相结合，提供了一种控制 API 访问和资源访问的安全方法。UGS 提供了与本文档中所述的 API 授权配合使用的 [Authentication](/authentication.md) 解决方案。

如果没有身份验证，任何人都可以访问 API 并可能执行未经授权的操作。例如，如果 API 允许用户查看敏感信息或更改数据，但没有设置身份验证，那么任何人都可以访问这些信息或在未经许可的情况下进行更改。

身份验证是为了确定用户的身份，而授权是为了控制用户可以执行的操作。身份验证为执行授权提供了必要的基础。身份验证就像是打开 API 大门的钥匙，而授权则决定用户是否被允许进门，以及进门后可以做什么。

## 访问控制的工作原理##how-access-control-works

UGS 中的访问控制是使用资源策略进行配置的。UGS 服务强制执行一些规则，规定谁可以访问这些服务以及他们可以执行哪些操作。

当用户尝试访问某个 UGS 服务时，该服务会根据配置的策略检查用户的身份，然后决定拒绝还是允许 API 请求。

一个资源策略是一系列语句的集合。这些语句按照用户的身份（Principal 属性）、限制或允许（Effect 属性）的操作（Action 属性）以及策略适用的资源（Resource 属性）进行定义。策略还包含“Sid”属性（语句标识符），这是用户为给定策略定义的描述性名称，只能包含字母数字字符和连字符。

策略中的资源被定义为统一资源名称 ([URN](https://en.wikipedia.org/wiki/Uniform_Resource_Name))，通常以构成 URN 组成部分的 API 路径结尾。

资源策略是根据每个项目或每个玩家进行配置的。项目策略将针对该项目中所有调用 UGS 服务的主体接受评估。玩家策略仅针对项目和环境范围内的单个玩家接受评估。

以下是 Economy 服务的一个有效 URN 的示例：

```text
urn:ugs:economy:/v2/project/*/player/*/currencies/gold
```

此处使用 glob 模式来匹配一组共用某种模式的资源。以下是此 URN 的不同组成部分。

| URN 组成部分         | 描述                                                                                                       |
| ---------------- | -------------------------------------------------------------------------------------------------------- |
| urn:             | 此前缀表明该字符串是 URN。                                                                                          |
| ugs:             | URN 的命名空间标识符 (NID)，用于标识负责维护此命名空间中的 URN 的组织或组。在此例中，“ugs”代表 Unity Gaming Services（Unity 游戏服务），是创建此 URN 的组。 |
| economy:         | 命名空间内的特定命名机构，用于标识 UGS 的特定区域。                                                                             |
| /v2/project/     | URN 的特定分段，用于标识 API 的版本以及 URN 适用的项目。                                                                      |
| \*               | 第一个与任意字符匹配的 glob 模式。这是一个代表任何可能值的通配符。在此例中，它将匹配以“urn:ugs:economy:/v2/project/”开头且后跟任意字符的任何 URN。            |
| /player/         | URN 的特定分段，用于标识 URN 适用的玩家。                                                                                |
| \*               | 第二个与任意字符匹配的 glob 模式。在此例中，它将匹配以“urn:ugs:economy:/v2/project/\*/player/”开头且后跟任意字符的任何 URN。                  |
| /currencies/gold | 这是 URN 的特定分段，用于标识 URN 适用的特定货币类型。                                                                         |

由于 URN 匹配过程使用 glob 模式，因此上述 URN 也可以定义如下。

`urn:ugs:economy:/**/currencies/gold`

当未创建访问控制策略时，访问控制默认为允许经过身份验证的玩家的所有经过身份验证的 API 调用。这种情况可以用以下资源策略来进行描述。

```text
{
	"Sid": "allow-all-ugs",
	"Effect": "Allow",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:*"
},
```

以下示例显示了如何创建有效的策略，以允许经过身份验证的玩家通过 API 调用读取但不能更改（写入）Economy 中的黄金货币。

```text
{
	"Sid": "deny-economy-write-access",
	"Effect": "Deny",
	"Action": ["Write"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:/v2/project/*/player/*/currency/gold"
},
```

或者，若要完全拒绝经过身份验证的玩家访问 Economy 中的所有 API，可以创建以下策略：

```text
{
	"Sid": "deny-all-economy-access",
	"Effect": "Deny",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:*"
},
```

## 如何使用访问控制##how-to-use-access-control

使用 [REST API](https://services.docs.unity.com/access) 或 [UGS CLI](./ugs-cli-introduction.md) 为 UGS 创建资源策略。这些策略只需创建一次，并在经过身份验证的调用方的上下文中针对 UGS 的每个 API 调用进行评估和执行。

### 示例策略##example-policies

不允许玩家执行任何 Cloud Code 脚本：

```text
{
	"Sid": "deny-cloud-code-access",
	"Effect": "Deny",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:cloud-code:/v1/projects/*/scripts/*"
},
```

此资源策略在玩家经过身份验证的项目中拒绝 Cloud Code 脚本的所有操作。Cloud Code 仅提供“执行”API 作为对该 API 的 POST 请求，这属于上述策略语句中的“写入”操作。

以下是 Cloud Save 资源策略的另一个示例：

```text
{
	"Sid": "deny-cloud-save-data-write-access",
	"Effect": "Deny",
	"Action": ["Write"],
	"Principal": "Player",
	"Resource": "urn:ugs:cloud-save:/v1/data/projects/*/players/*/items**"
},
```

此资源策略拒绝任何经过身份验证的玩家对项目的所有 Cloud Save 数据进行写入访问，包括具有 `Player` 身份的用户或组对项下所有嵌套路径和子文件夹的写入访问。此策略实际上会阻止玩家直接将数据写入 Cloud Save。通过将此策略与先前的 Cloud Code 策略相结合，意味着开发者可以通过 Cloud Code 将数据写入 Cloud Save，并在 Cloud Code 中实现任何其他游戏逻辑。

以下说明了构成策略的不同组成部分及其作用。

| 语句属性      | 可接受的值                                         | 描述                                                                                                                                                                                   |
| --------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Sid       | 字母数字字符串，例如 `^[A-Za-z0-9][A-Za-z0-9_-]{5,59}$` | 语句标识符。在此策略的每个环境中具有唯一性，用于提供人类可读的策略名称。有效值必须包含 5 到 59 个字符。例如，`deny-cloud-save-data-write-access`。                                                                                       |
| Effect    | Allow、Deny                                    | 用于指定此策略是允许还是拒绝对指定资源的访问。                                                                                                                                                              |
| 操作        | Write、Read、\*                                 | 用于指定允许或拒绝的访问类型。这些操作针对 UGS 中的各种产品。  Write 值通常指一些会改变 UGS 服务状态的操作。UGS API 的 POST、PUT、PATCH、DELETE HTTP 动词属于此类别。Read 值通常指一些从 UGS 服务中获取状态的操作。UGS API 的 GET HTTP 动词属于此类别。\* 值表示包括所有可接受的操作。 |
| Principal | 玩家                                            | 用于指定策略适用的用户身份。当前唯一可接受的值是“Player”。                                                                                                                                                    |
| Resource  | 有效的 UGS URN                                   | 用于指定策略适用的一个或多个资源。例如，可以将资源设置为 `urn:ugs:cloud-save:/v1/data/projects/*/players/*/items**`，这是一个具有 glob 模式的 URN，用于匹配项目中经过身份验证的玩家的 Cloud Save 数据，包括项下的所有嵌套路径和子路径。                         |

### 错误响应##error-responses

当玩家尝试访问他们没有适当权限的资源时，系统将返回错误响应，状态代码为 403 Forbidden。错误响应的具体格式取决于现有访问控制策略的类型。

如果按照基于项目的策略限制玩家访问资源，则错误响应包括以下字段：

```text
{
  "title": "Forbidden",
  "detail": "Access has been restricted",
  "code": 56,
  "status": 403,
  "type": "https://services.docs.unity.com/docs/errors/#56"
}
```

如果按照基于玩家的策略限制玩家访问资源，则错误响应包括以下字段：

```text
{
  "title": "Forbidden",
  "detail": "Principal is not authorized to access resource",
  "code": 57,
  "status": 403,
  "type": "https://services.docs.unity.com/docs/errors/#57"
}
```

如果玩家被暂时封禁，错误响应还会包含一个 `expiresAt` 字段，指明封禁到期时间：

```text
{
  "title": "Forbidden",
  "detail": "Principal is not authorized to access resource",
  "code": 57,
  "status": 403,
  "type": "https://services.docs.unity.com/docs/errors/#57",
  "expiresAt": "2023-04-29T18:30:51.243Z"
}
```

如果玩家被永久封禁，错误响应将不包含 `expiresAt` 字段。您应该在应用程序代码中适当处理这些错误响应，以确保流畅的用户体验。

## 访问控制的策略选择##policy-selection-in-access-control

在评估访问控制策略时，只有最具体的规则才会胜出，并应用其效果。

以下是三个策略示例。

```text
{
	"Sid": "deny-all-economy-access",
	"Effect": "Deny",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:*"
},
{
	"Sid": "allow-economy-currencies-access",
	"Effect": "Allow",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:/v2/**/currencies/*"
},
{
	"Sid": "deny-gold-currency-access-economy",
	"Effect": "Deny",
	"Action": ["Write"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:/v2/**/currencies/gold"
},

```

1. 第一条规则是对 Economy 的所有请求的通用拒绝规则
2. 第二条规则允许对 Economy 中 `*/currencies/` API 的所有请求进行读写访问
3. 第三条规则明确拒绝对 Economy 中 `*/currencies/gold` API 的写入请求进行访问

如果对 `*/currencies/silver` 发出请求，则会应用第二条规则，即允许 `/currencies/*`，因为这条规则比第一条规则更具体。

如果对 `*/currencies/gold` 发出请求，则会应用第三条规则，即拒绝 `*/currencies/gold`，因为这条规则是与请求匹配的最具体规则。

如果有多个策略列出完全相同的 Resource，则 Deny Effect 始终优先。

## 最佳实践##resource-urns-and-query-parameter-handling

### 默认拒绝##rules-for-query-parameter-handling-in-resource-urns

首先采用默认策略拒绝所有访问，然后显式授予对特定 API 或资源的访问。

```text
{
	"Sid": "deny-all-ugs-access",
	"Effect": "Deny",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:*:/**"
},
```

### 最低权限原则##backward-compatibility

仅授予 API 或资源所需的最低权限。

```text
{
	"Sid": "allow-cloud-save-read-access",
	"Effect": "Allow",
	"Action": ["Read"],
	"Principal": "Player",
	"Resource": "urn:ugs:cloud-save:/v1/data/**/player/*/items**"
},
```

### 定义精细策略##deny-by-default

为特定的 API 方法和资源创建策略，而不是为所有 API 和资源创建策略。

```text
{
	"Sid": "allow-economy-silver-readwrite-access",
	"Effect": "Allow",
	"Action": ["*"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:/**/currencies/silver"
},
{
	"Sid": "deny-economy-gold-write-access",
	"Effect": "Deny",
	"Action": ["Write"],
	"Principal": "Player",
	"Resource": "urn:ugs:economy:/**/currencies/gold"
},
```

### 定期审查##least-privilege-principle

定期审查和更新 API 策略，以确保策略反映游戏的当前状态，并移除不必要的权限。

## REST API##best-practices

访问控制 API 可以通过 Web 终端或 REST API 进行访问。REST API 提供更大的灵活性，让您可以利用喜欢的语言和游戏开发引擎来自动执行工作流程。

请参阅[访问控制 REST API 文档](https://services.docs.unity.com/access/index.html)以了解更多信息。请参阅[服务帐户身份验证文档](https://services.docs.unity.com/docs/service-account-auth)以详细了解如何对 API 调用进行身份验证。

以下示例显示了如何使用 REST API 与 cURL 工具来设置资源策略。

```text
curl -X PATCH https://services.api.unity.com/access/v1/projects/{projectId}/environments/{environmentId}/resource-policy \
--header 'Authorization: Basic YOUR_ENCODED_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '
{
     "statements": [
    	{
            	"Sid": "deny-cloud-save-write-access",
            	"Effect": "Deny",
            	"Action": ["Write"],
            	"Principal": "Player",
            	"Resource": "urn:ugs:cloud-save:*"
    	}
    ]
}'
```

## 部署访问控制配置##rest-api

要应用您的配置，必须将配置部署到访问控制服务。

### 使用编辑器进行部署##define-fine-grained-policies

要在 Unity 编辑器中部署访问控制配置，必须先安装所需的包，然后将 [Unity Gaming Services（Unity 游戏服务）项目](/cloud/projects.md)关联到 Unity 编辑器。

### 关联项目##service-urns

将 [Unity Gaming Services（Unity 游戏服务）项目](/cloud/projects.md)与 Unity 编辑器关联。您可以在 Unity Dashboard 中找到您的 UGS Project ID。

1. 在 Unity 编辑器中，选择 **Edit（编辑）**> **Project Settings（项目设置）**> **Services（服务）**。

2. 关联您的项目。

   * 如果项目没有 Unity Project ID：

     1. 选择 **Create a Unity Project ID（创建 Unity Project ID）**> **Organizations（组织）**，然后从下拉菜单中选择一个组织。
     2. 选择 **Create project ID（创建 Project ID）**。

   * 如果已有 Unity Project ID：

     1. 选择 **Use an existing Unity project ID（使用现有 Unity Project ID）**。
     2. 从下拉菜单中选择组织和项目。
     3. 选择 **Link project ID（关联 Project ID）**。

此时将显示您的 Unity Project ID，并且项目现在已关联到 Unity 服务。此外，还可以使用 `UnityEditor.CloudProjectSettings.projectId` 在 Unity 编辑器脚本中访问您的 Project ID。

### 安装所需的包##regular-review

要在编辑器中创建访问控制配置，必须安装以下包：

* [Deployment](https://docs.unity3d.com/Packages/com.unity.services.deployment@latest)
* [Services Tooling](https://docs.unity3d.com/Packages/com.unity.services.tooling@latest)

> **Note:**
>
> 请查看 [Unity - 手册：Package Manager（包管理器）窗口](https://docs.unity3d.com/Manual/upm-ui.html)，熟悉 Unity Package Manager（包管理器）界面。

安装这些包并将它们添加到可用包列表中：

1. 在 Unity 编辑器的 Package Manager（包管理器）窗口中，选择 **+（添加）**> **Add package by name...（按名称添加包...）**。
2. 输入 `com.unity.services.deployment`。
3. 选择 **Add（添加）**。
4. 对 `com.unity.services.tooling` 重复以上步骤。

### 创建配置##deploying-with-the-editor

请按照以下步骤创建访问控制配置：

1. 在 Unity 编辑器中，右键单击 Project（项目）窗口，然后选择 **Create（创建）**> **Services（服务）**> **Access Control Configuration（访问控制配置）**。
2. 根据需要为配置命名。
3. 按 **Enter（输入）**。

现在，新配置会显示在 Project（项目）窗口和 Deployment（部署）窗口中；可通过选择 **Window（窗口）**> \*\*Deployment（部署）\*\*来访问 Deployment（部署）窗口。

### 编辑配置##link-project

有两种方法可以编辑现有的访问控制配置：

* 在 Project（项目）选项卡中，双击现有配置。
* 在 Deployment（部署）窗口中，找到现有配置，然后从右键单击菜单中选择 **Open（打开）**。

### 使用 CLI 进行部署##install-required-packages

使用 [UGS 访问控制 CLI](https://services.docs.unity.com/guides/ugs-cli/latest/access/Access%20Command%20Line/overview) 可以更轻松地管理和自动进行访问控制配置。

#### 配置 UGS CLI##urns-with-query-parameters

按照以下步骤操作以开始使用 UGS CLI：

1. [安装 UGS CLI](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/install-the-cli/)。
2. 按如下方式配置 Project ID 和环境：
   `ugs config set project-id <your-project-id>`
   `ugs config set environment-name <your-environment-name>`
3. 为服务帐户配置[访问控制](https://services.docs.unity.com/docs/service-account-auth/index.html#project-resource-policy-editor)和[环境管理](https://services.docs.unity.com/docs/service-account-auth/index.html#unity-environments-admin)所需的角色。请参阅[接受身份验证](https://services.docs.unity.com/guides/ugs-cli/latest/general/get-started/get-authenticated/)。

#### 部署资源##urns-with-a-wildcard

运行以下命令：

`ugs deploy <path-to-access-control-file>`
