> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Token 的文档

# CREATE TOKEN

为当前用户创建一个标记：服务器会生成一个随机密钥，将其作为附加的[身份验证方法](/docs/zh/reference/statements/create/user#identification)添加到当前用户，并将其作为查询结果返回。该密钥仅在本次查询中显示这一次——它以哈希形式存储，此后无法恢复。

语法：

```sql theme={null}
CREATE TOKEN
    [{VALID UNTIL datetime | VALID FOR interval}]
    [GRANTS (privilege ON object [,...])]
```

这是 `ALTER USER <current user> ADD IDENTIFIED WITH sha256_password BY '<random secret>'` 的简写形式，
并带有相同的 [`VALID UNTIL`](/docs/zh/reference/statements/create/user#valid-until-clause) 和
[`GRANTS`](/docs/zh/reference/statements/create/user#grants-clause) 子句，因此标记的行为与当前用户的普通密码一致：

* 它与用户绑定——在 `system.query_log` 和 `system.processes` 中显示为该用户，用户被删除后它随之失效，
  用户失去访问权限时它也会一并失去；
* 可以通过 `VALID UNTIL` 或 `VALID FOR` 限制其有效期，通过 `GRANTS` 限制其特权；
* 可用于任何接受密码的身份验证机制，例如 HTTP 接口的 `password` 参数或 ClickHouse 客户端的 `--password` 选项。

创建标记需要 `CREATE TOKEN` 特权，或对当前用户拥有 `ALTER USER` 特权。
之所以将其设为单独的特权，是因为标记会降低其所属账户的安全级别：使用硬件密钥或证书
完成身份验证的用户，可以借此为同一账户创建一个长期有效的密码。该特权同样授权执行等价的
`ALTER USER <current user> ADD IDENTIFIED ...` 语句。

## 结果

该查询返回一行,包含两列:

| 列 | 类型 | 描述 |
| - | - | - |
| `token` | `String` | 生成的密钥。 |
| `valid_until` | `DateTime64(0)` | 标记的过期时间。`0` 表示永不过期,其编码方式与 [`system.users`](/docs/zh/reference/system-tables/users) 的 `valid_until` 列相同。 |

若要获取不带任何格式的密钥,请使用 `FORMAT TSVRaw` 进行查询:

```sql theme={null}
CREATE TOKEN VALID FOR INTERVAL 30 DAY GRANTS (SELECT ON db.*) FORMAT TSVRaw
```

该密钥长度为 32 个字符，由加密安全的随机源生成，因此无需 (实际上也不会) 依据
[密码复杂度规则](/docs/zh/reference/statements/create/user#identification)进行校验——这些规则的存在是为了
约束由人工设置的密码。

## VALID UNTIL 与 VALID FOR 子句

用于限制标记的有效期。它们的作用与 [`CREATE USER`](/docs/zh/reference/statements/create/user#valid-until-clause) 中身份验证方法的同名子句完全一致：`VALID UNTIL` 接受一个绝对的日期和时间，`VALID FOR` 接受一个[时间间隔](/docs/zh/reference/data-types/special-data-types/interval)，该间隔会与查询执行时的当前时间相加。

若两个子句均未指定，标记的有效期取
[`create_token_default_ttl_seconds`](/docs/zh/reference/settings/session-settings/create) 的值，默认为
30 分钟，因此未显式延长有效期的标记均为短期标记。将该设置设为 `0`，或
写作 `VALID UNTIL 'infinity'`，即可创建永不过期的标记。

示例：

* `CREATE TOKEN VALID UNTIL '2026-12-31'`
* `CREATE TOKEN VALID FOR INTERVAL 30 DAY`
* `CREATE TOKEN VALID UNTIL 'infinity'`

## GRANTS 子句

将使用该标记完成身份验证的会话的访问权限限制为与所列特权的交集。其工作方式与 [`CREATE USER` 的 `GRANTS` 子句](/docs/zh/reference/statements/create/user#grants-clause)完全一致，包括其各项限制——尤其需要注意的是，该限制仅在接收查询的节点上生效，不会传播到集群中的其他节点。该子句绝不会新增任何访问权限：未授予该用户的特权对标记而言同样不可用。若不使用该子句，标记将拥有该用户的全部访问权限。

示例：

* `CREATE TOKEN GRANTS (SELECT ON db.table)`
* `CREATE TOKEN VALID FOR INTERVAL 90 DAY GRANTS (SELECT ON db.table, INSERT ON db.table)`

无论是该权限限制还是时间限制，都不适用于标记的会话所遗留下来的内容——参见[安全方面的考虑](#security-considerations)。

## 管理标记

标记是用户的一种身份验证方法，因此它会在
[`SHOW CREATE USER`](/docs/zh/reference/statements/show#show-create-user) 的输出中列出 (含其 `VALID UNTIL` 和 `GRANTS` 子句，
但不含密钥) ，也会出现在 [`system.users`](/docs/zh/reference/system-tables/users) 表的 `auth_type`、`auth_params` 和 `auth_grants` 列中。

没有可用于删除单个标记的语句。若要吊销某个用户的全部标记，可替换其
身份验证方法，例如执行 `ALTER USER <name> IDENTIFIED WITH ...`，或执行
`ALTER USER <name> RESET AUTHENTICATION METHODS TO NEW` 以仅保留最近添加的那一个。用户同时可拥有的
身份验证方法数量受 `max_authentication_methods_per_user` 服务器设置的限制。

密钥由查询本身生成并存储，因此，若某个 `CREATE TOKEN` 的结果始终未能送达
客户端——例如在发送该行时连接中断，或客户端无法打开 `INTO OUTFILE` 指定的文件——
就会遗留一个无人能用、却仍计入上述上限的身份验证方法。没有任何人持有这样的密钥：它只在查询运行期间存在。
而在开始运行前就被拒绝的查询 (包括 `FORMAT` 子句指定了不可用格式的查询) 则不会新增任何内容。

`CREATE TOKEN` 不支持 `ON CLUSTER` 子句。若集群的访问实体存储在本地，请使用复制式访问存储 (或在每个
节点上执行等效的 `ALTER USER ... ADD IDENTIFIED WITH sha256_hash` 语句) ，以使标记在整个集群范围内生效。

## 安全方面的考虑

`VALID UNTIL` 和 `GRANTS` 约束的是使用该 标记 进行身份验证的 会话，但并不约束这些 会话 所遗留下来的东西：

* 截止时间仅在 会话 使用该 标记 进行身份验证时检查。对于已经建立的 会话 以及正在运行的查询，标记 过期时并不会将其中断。
* 会话 创建的一切都会比 标记 存活得更久，而能够自行运转的对象会一直运转下去：
  [可刷新materialized view](/docs/zh/reference/statements/create/view#refreshable-materialized-view) 会持续刷新，
  挂载在流式表引擎 (例如
  [`Kafka`](/docs/zh/reference/engines/table-engines/integrations/kafka)、
  [`RabbitMQ`](/docs/zh/reference/engines/table-engines/integrations/rabbitmq)、
  [`NATS`](/docs/zh/reference/engines/table-engines/integrations/nats) 或
  [`S3Queue`](/docs/zh/reference/engines/table-engines/integrations/s3queue)) 上的 materialized view 会持续消费，
  带有 [`LIFETIME`](/docs/zh/reference/statements/create/dictionary/lifetime) 的字典也会持续重新加载，即便 标记 早已过期。
  VIEW 是以其 [`DEFINER`](/docs/zh/reference/statements/create/view#sql_security) 的权限来完成这些工作的，该 DEFINER 默认就是创建该
  VIEW 的用户 —— 用的是该用户的全部权限，而不是 标记 的 `GRANTS` 子句为其保留的那部分权限。

因此，允许创建表、VIEW 或字典的 标记，实际上可以同时突破这两项限制：它可以留下一个持久化任务，在截止时间之后继续运行，并以用户的权限执行 标记 本身无权执行的操作。只授予 标记 应用程序确实需要的权限 —— 通常是对指定表的 `SELECT` 和 `INSERT` —— 若希望这些限制真正生效，就不要把 `CREATE TABLE`、`CREATE VIEW`、`CREATE DICTIONARY` 以及 `ACCESS MANAGEMENT` 特权写进它的 `GRANTS` 子句。

使用带有 `GRANTS` 子句的 标记 完成身份验证的 会话 根本无法签发 标记：此类 会话 被禁止为现有用户添加身份验证方法。新身份验证方法的 `GRANTS` 子句在登录时是与该用户的访问权限取交集，而非与创建该方法的 会话 的权限取交集，否则这就会成为一条扩大限制范围的途径。
