fix(access): 统一 API Key 模型权限与列表契约
将全局启用、用户组基线、API Key 专属或排除规则及 scope 按固定顺序求值,避免 Key 越过所属用户组权限,并让运行时候选与模型列表共用同一权限链。 新增 Key 级可分配模型与失效规则诊断接口、OpenAI 兼容 /v1/models 及 rich 列表迁移路径;前端权限弹窗改为按当前 Key 实时加载并支持清理失效规则。 验证:Go 全量测试与 go vet 通过;Web 22 个测试文件共 142 项通过;pnpm lint、pnpm openapi、pnpm build、Compose 配置、gofmt、ShellCheck 和 git diff --check 通过;独立 PostgreSQL 真实配置验收通过。
This commit is contained in:
+244
-26
@@ -5726,6 +5726,7 @@
|
||||
"api-keys"
|
||||
],
|
||||
"summary": "列出 API Key 可分配模型",
|
||||
"deprecated": true,
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -5809,6 +5810,64 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/api-keys/{apiKeyID}/assignable-models": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "返回指定 API Key 所属用户组允许、全局启用且符合 KEY scope 的平台来源,并附带已有规则有效性诊断。",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"api-keys"
|
||||
],
|
||||
"summary": "列出指定 API Key 可分配模型",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "API Key ID",
|
||||
"name": "apiKeyID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.APIKeyAssignableModelsResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "Service Unavailable",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/api-keys/{apiKeyID}/disable": {
|
||||
"patch": {
|
||||
"security": [
|
||||
@@ -7318,26 +7377,15 @@
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "按当前用户权限返回可用于 Playground 或 API 调用的模型列表。",
|
||||
"description": "兼容期 rich 平台来源明细;新客户端应改用 /api/v1/platform-models,OpenAI 客户端使用 /v1/models。",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"playground"
|
||||
],
|
||||
"summary": "列出可调用模型",
|
||||
"parameters": [
|
||||
{
|
||||
"enum": [
|
||||
"canvas_model_node",
|
||||
"desktop"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "模型可选场景;不传时保持原有行为",
|
||||
"name": "usage_scene",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"summary": "列出可调用平台模型(已弃用)",
|
||||
"deprecated": true,
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -7345,12 +7393,6 @@
|
||||
"$ref": "#/definitions/httpapi.PlatformModelListResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
@@ -7362,12 +7404,6 @@
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7682,6 +7718,67 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/platform-models": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "按当前用户权限返回可用于 Playground 或 API 调用的模型列表。",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"playground"
|
||||
],
|
||||
"summary": "列出可调用模型",
|
||||
"parameters": [
|
||||
{
|
||||
"enum": [
|
||||
"canvas_model_node",
|
||||
"desktop"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "模型可选场景;不传时保持原有行为",
|
||||
"name": "usage_scene",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.PlatformModelListResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/platforms": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -10240,6 +10337,43 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/models": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "按当前身份、API Key 访问规则及 scope 返回去重后的逻辑模型列表。",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"openai-compatible"
|
||||
],
|
||||
"summary": "列出 OpenAI 兼容模型",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.OpenAIModelListResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
@@ -10314,6 +10448,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpapi.APIKeyAssignableModelsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/store.PlatformModel"
|
||||
}
|
||||
},
|
||||
"ruleDiagnostics": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/store.APIKeyAccessRuleDiagnostic"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpapi.APIKeyListResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -11674,6 +11825,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpapi.OpenAIModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "integer",
|
||||
"example": 1710000000
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"example": "gpt-4o-mini"
|
||||
},
|
||||
"object": {
|
||||
"type": "string",
|
||||
"example": "model"
|
||||
},
|
||||
"owned_by": {
|
||||
"type": "string",
|
||||
"example": "easyai"
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpapi.OpenAIModelListResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/httpapi.OpenAIModel"
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "string",
|
||||
"example": "list"
|
||||
}
|
||||
}
|
||||
},
|
||||
"httpapi.PlatformListResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -13123,6 +13310,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"store.APIKeyAccessRuleDiagnostic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"type": "string"
|
||||
},
|
||||
"effective": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"resource_unavailable",
|
||||
"owner_access_revoked",
|
||||
"scope_not_allowed"
|
||||
]
|
||||
},
|
||||
"resourceId": {
|
||||
"type": "string"
|
||||
},
|
||||
"resourceName": {
|
||||
"type": "string"
|
||||
},
|
||||
"resourceType": {
|
||||
"type": "string"
|
||||
},
|
||||
"ruleId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"store.AcceptanceRun": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user