跳到主要内容

管理

后端 API​

管理模块涵盖 llm_d_lens/auth/router.py 中的身份验证路由,以及 llm_d_lens/db/system_router.py 中的系统设置路由。

身份验证与管理相关路由位于 llm_d_lens/auth/router.py 中的 /api/v1 前缀下。

资源绑定限制​

模型推理授权替代了部署分享。资源级绑定只接受 scopeResourceType: "model_service_group" 和内置 end-user 的 roleId。 模型 ID 与集群必须匹配已存储记录,授权对象必须独立具备该集群的推理权限。 全局和集群级角色分配不变。

这些限制适用于 POST /api/v1/users/{user_id}/role-bindings 和 POST /api/v1/groups/{group_id}/role-bindings,二者都要求角色绑定管理权限。 成功创建返回 HTTP 201 和绑定记录。

{
"roleId": "existing-built-in-end-user-role-id",
"scopeType": "resource",
"scopeClusterId": "cluster-id",
"scopeResourceType": "model_service_group",
"scopeResourceId": "msg-existing-model-id"
}

已退役的部署资源类型、特权授权角色和集群不匹配都会被拒绝。 日常模型授权请使用带 scope 校验的模型访问 API, 由服务器推导角色及集群,而不是接受调用方指定的值。

列出用户​

列出用户,包括直接角色、群组成员关系以及继承的角色。

GET /api/v1/users

请求:

  • 查询参数:
    • query(string,可选):按用户名或其他用户搜索文本进行过滤。
    • status(string,可选):按用户状态过滤,例如 active 或 disabled。

该端点没有请求体。

响应:

返回用户记录数组,并附带直接 roles(角色)、groups(群组)和 inheritedRoles(继承角色)信息。

[
{
"username": "alice",
"display_name": "Alice Admin",
"id": "user-1",
"email": "alice@example.com",
"provider_id": null,
"auth_source": "local",
"external_id": null,
"status": "active",
"failed_login_count": 0,
"locked_until": null,
"must_change_password": false,
"password_changed_at": "2026-09-21T08:00:00+00:00",
"last_login_at": "2026-09-23T08:45:00+00:00",
"principal_version": 3,
"created_at": "2026-09-20T10:00:00+00:00",
"updated_at": "2026-09-23T08:45:00+00:00",
"has_password": true,
"protected": false,
"roles": [
{
"name": "maintainer",
"scopeType": "cluster",
"scopeClusterId": "cluster-123"
}
],
"groups": [
{
"id": "group-ops",
"name": "ops",
"source": "manual"
}
],
"inheritedRoles": [
{
"name": "end-user",
"scopeType": "global",
"scopeClusterId": null,
"scopeResourceType": null,
"scopeResourceId": null,
"groupId": "group-ops",
"groupName": "ops"
}
]
}
]

创建用户​

创建一个用户账户。

POST /api/v1/users

请求:

  • JSON 请求体字段:
    • username(string,必填)
    • password(string,可选)
    • displayName(string,可选)
    • email(string,可选)
{
"username": "alice",
"password": "<strong-password>",
"displayName": "Alice Admin",
"email": "alice@example.com"
}

响应:

返回由 _user_public(...) 生成的新建用户记录。

{
"username": "alice",
"display_name": "Alice Admin",
"id": "user-1",
"email": "alice@example.com",
"provider_id": null,
"auth_source": "local",
"external_id": null,
"status": "active",
"failed_login_count": 0,
"locked_until": null,
"must_change_password": false,
"password_changed_at": null,
"last_login_at": null,
"principal_version": 1,
"created_at": "2026-09-23T09:00:00+00:00",
"updated_at": "2026-09-23T09:00:00+00:00",
"has_password": true,
"protected": false
}

更新用户​

更新用户的显示名称、邮箱或状态。

PATCH /api/v1/users/{user_id}

请求:

  • 路径参数:
    • user_id(string,必填):要更新的用户记录。
  • JSON 请求体字段:
    • displayName(string,可选)
    • email(string,可选)
    • status(string,可选)
{
"displayName": "Alice Operations",
"email": "alice.ops@example.com",
"status": "active"
}

响应:

返回更新后的用户记录。

{
"username": "alice",
"display_name": "Alice Operations",
"id": "user-1",
"email": "alice.ops@example.com",
"provider_id": null,
"auth_source": "local",
"external_id": null,
"status": "active",
"failed_login_count": 0,
"locked_until": null,
"must_change_password": false,
"password_changed_at": null,
"last_login_at": "2026-09-23T08:45:00+00:00",
"principal_version": 2,
"created_at": "2026-09-20T10:00:00+00:00",
"updated_at": "2026-09-23T09:05:00+00:00",
"has_password": true,
"protected": false
}

列出角色​

列出角色。

GET /api/v1/roles

请求:

该端点没有请求体。

响应:

返回角色记录数组,其中包含已解析的权限码。

[
{
"name": "maintainer",
"description": "Manage clusters and workloads",
"id": "role-maintainer",
"is_builtin": true,
"created_at": "2026-09-20T09:00:00+00:00",
"updated_at": "2026-09-20T09:00:00+00:00",
"permissions": [
"cluster:cluster:read",
"deployment:run:read",
"session:session:revoke"
]
}
]

创建角色​

创建一个角色。

POST /api/v1/roles

请求:

  • JSON 请求体字段:
    • name(string,必填)
    • description(string,可选)
    • permissions(array<string>,可选)
{
"name": "auditor",
"description": "Read-only compliance role",
"permissions": [
"deployment:run:read",
"cluster:cluster:read"
]
}

响应:

返回新建角色及其权限集合。

{
"name": "auditor",
"description": "Read-only compliance role",
"id": "role-auditor",
"is_builtin": false,
"created_at": "2026-09-23T09:10:00+00:00",
"updated_at": "2026-09-23T09:10:00+00:00",
"permissions": [
"cluster:cluster:read",
"deployment:run:read"
]
}

设置角色权限​

设置自定义角色的权限。

PUT /api/v1/roles/{role_id}/permissions

请求:

  • 路径参数:
    • role_id(string,必填):要更新的自定义角色。
  • JSON 请求体字段:
    • permissions(array<string>,必填)
{
"permissions": [
"cluster:cluster:read",
"deployment:run:read",
"session:session:revoke"
]
}

响应:

当权限集合成功保存时,返回 204 No Content。该端点不返回 JSON 响应体。

列出会话​

列出会话;管理员可以包含已吊销的会话,而其他调用者只能看到自己的会话。

GET /api/v1/sessions

请求:

  • 查询参数:
    • include_revoked(boolean,可选):管理员可以在结果集中包含已吊销的会话。

该端点没有请求体。

响应:

返回会话记录列表。管理员调用者会收到每个会话以及 username 字段;非管理员调用者只能收到自己的会话。

[
{
"user_id": "user-1",
"token_hash": "$argon2id$v=19$m=65536,t=3,p=4$sessionhash",
"id": "session-1",
"created_at": "2026-09-23T08:45:00+00:00",
"expires_at": "2026-09-23T16:45:00+00:00",
"idle_expires_at": "2026-09-23T10:45:00+00:00",
"last_seen_at": "2026-09-23T09:15:00+00:00",
"revoked_at": null,
"auth_source": "local",
"ip": "127.0.0.1",
"user_agent": "Mozilla/5.0",
"username": "alice"
}
]

吊销会话​

吊销一个会话。

DELETE /api/v1/sessions/{session_id}

请求:

  • 路径参数:
    • session_id(string,必填):要吊销的会话记录。

该端点没有请求体。

响应:

目标会话被吊销后,返回 204 No Content。该端点不返回 JSON 响应体。

列出集群访问绑定​

列出某个集群的集群级访问绑定。

GET /api/v1/clusters/{cluster_id}/access

请求:

  • 路径参数:
    • cluster_id(string,必填):要列出其用户和群组绑定的集群。

该端点没有请求体。

响应:

返回用户和群组绑定的列表,每条记录都标有 subjectType。

[
{
"subjectType": "user",
"user_id": "user-1",
"role_id": "role-maintainer",
"id": "binding-user-1",
"scope_type": "cluster",
"scope_cluster_id": "cluster-123",
"scope_resource_type": null,
"scope_resource_id": null,
"granted_by_user_id": "admin-1",
"expires_at": null,
"created_at": "2026-09-23T09:20:00+00:00"
},
{
"subjectType": "group",
"group_id": "group-ops",
"role_id": "role-end-user",
"id": "binding-group-1",
"scope_type": "cluster",
"scope_cluster_id": "cluster-123",
"scope_resource_type": null,
"scope_resource_id": null,
"granted_by_user_id": "admin-1",
"expires_at": null,
"created_at": "2026-09-23T09:21:00+00:00"
}
]

授予集群访问权限​

向用户或群组授予集群级访问权限。

POST /api/v1/clusters/{cluster_id}/access

请求:

  • 路径参数:
    • cluster_id(string,必填):该绑定的权威集群范围。
  • JSON 请求体字段:
    • subjectType("user" | "group",必填)
    • subjectId(string,必填)
    • roleId(string,必填)
    • clusterId(string,可选):出现在请求模型中,但路由实际使用 {cluster_id} 路径参数作为作用域。
{
"subjectType": "user",
"subjectId": "user-1",
"roleId": "role-maintainer"
}

响应:

返回新建的绑定记录。

{
"user_id": "user-1",
"role_id": "role-maintainer",
"id": "binding-user-1",
"scope_type": "cluster",
"scope_cluster_id": "cluster-123",
"scope_resource_type": null,
"scope_resource_id": null,
"granted_by_user_id": "admin-1",
"expires_at": null,
"created_at": "2026-09-23T09:20:00+00:00"
}

撤销集群访问权限​

撤销一个集群级访问绑定。

DELETE /api/v1/clusters/{cluster_id}/access/{binding_id}

请求:

  • 路径参数:
    • cluster_id(string,必填):要移除其绑定的集群。
    • binding_id(string,必填):要撤销的用户或群组绑定 ID。

该端点没有请求体。

响应:

绑定被移除后,返回 204 No Content。该端点不返回 JSON 响应体。

下面的数据库设置相关路由位于 llm_d_lens/db/system_router.py 中的 /api/v1/system 路径下。

读取数据库设置状态​

读取 Lens 自身的数据库是否已经配置完成。

GET /api/v1/system/database

请求:

该端点没有请求体。

响应:

返回一个 DatabaseStatus 对象。displayTarget 仅包含经过脱敏处理的主机/端口/数据库信息,绝不会回显凭据。

{
"configured": true,
"mode": "external",
"engine": "postgresql",
"displayTarget": "db.example.com:5432/prism"
}

配置后端数据库​

配置 Lens 自身的数据库连接(外部或内嵌),并创建初始数据表。

POST /api/v1/system/database

请求:

  • JSON 请求体字段:
    • mode("external" | "embedded",必填)
    • engine("postgresql" | "mysql" | "oracle" | "mssql",可选)
    • databaseUrl(string,external 模式下必填)
    • embeddedPassword(string,可选;仅在 embedded 模式下有意义)

外部数据库示例:

{
"mode": "external",
"engine": "mysql",
"databaseUrl": "mysql://prism:secret@db.example.com:3306/prism"
}

响应:

连接探测、引擎配置和初始数据表创建成功后,返回最终的 DatabaseStatus。

{
"configured": true,
"mode": "external",
"engine": "mysql",
"displayTarget": "db.example.com:3306/prism"
}

下面的主密钥相关路由同样位于 /api/v1/system/... 路径下,但它们是由 llm_d_lens/auth/router.py(而非 system_router.py)注册的,与其他身份验证及管理端点放在一起。

读取存储密钥主密钥状态​

读取当前生效的主密钥(LENS_SECRET_KEY)来源、不可逆指纹,以及现有的服务提供方密钥数量和旧的备用密钥数量。密钥本身的值永远不会被返回。

GET /api/v1/system/secret-key

请求:

该端点没有请求体。

响应:

{
"source": "file",
"envLocked": false,
"configured": true,
"fingerprint": "3f9a1c7b52e0d4a6",
"keyLength": 64,
"oldKeyCount": 1,
"path": "/home/user/.local/share/lens/credentials/master_key.json",
"providerSecretCount": 2
}

source 的取值为 environment、file 或 unconfigured;当 LENS_SECRET_KEY 通过环境变量提供时,envLocked 为 true(此时存储的密钥会被忽略,并且通过 API 进行密钥轮换的请求会被拒绝)。

轮换存储密钥主密钥​

生成一个新的主密钥(或使用指定的密钥),用它重新加密每一个已存储的服务提供方密钥,并保留此前的密钥作为解密回退。当 LENS_SECRET_KEY 被环境变量锁定时,该操作会被拒绝。

POST /api/v1/system/secret-key/rotate

请求:

  • JSON 请求体字段:
    • newKey(string,可选;留空则自动生成一个强密钥)
{
"newKey": "a-manually-chosen-strong-key"
}

响应:

返回新的状态,以及 rotatedSecrets(已重新加密的服务提供方密钥数量)。

{
"source": "file",
"envLocked": false,
"configured": true,
"fingerprint": "b71e0c9d3a4f8215",
"keyLength": 28,
"oldKeyCount": 1,
"path": "/home/user/.local/share/lens/credentials/master_key.json",
"providerSecretCount": 2,
"rotatedSecrets": 2
}

清除旧的主密钥​

在所有服务提供方密钥都已重新加密之后,删除保留的备用密钥。仍使用旧密钥加密的密钥将变得不可读,因此请先重新保存那些服务提供方的配置。

DELETE /api/v1/system/secret-key/old

请求:

该端点没有请求体。

响应:

返回 oldKeyCount 设为 0 的状态。

此外还存在其他身份验证端点,用于登录/会话状态、群组、身份提供方、审计日志、密码修改以及初始化引导;请参阅 OpenAPI 参考文档。

完整的请求/响应 Schema 请参阅 FastAPI OpenAPI schema(可通过 npm run docs:api 重新生成)。