feat(open): 服务身份免登录分页查询(REQ-20260921-0004)

- agent_scope 新增 service_enabled 标记(Flyway V7 + 回滚),服务 Token 签发
  由 sync 硬编码改为标记驱动,管理后台作用域 CRUD/前端支持该标记
- PermissionService 全部行过滤入口加 tenant_service 分支:服务主体总部视角
  全量可见不做行过滤,用户身份行为不变;非服务主体的 null user 显式拒绝
- warehouse.todo.list.query 按当前登录人统计,服务身份返回 PERMISSION_DENIED
- RateLimitService 新增 SERVICE-QUERY 独立限流档(默认 300/分钟)
- seed-dev.sql 新增 ops-query 作用域并绑定全部在线查询工具
- 文档:tools-reference §0.3、README Open API 服务 Token 段
This commit is contained in:
my_local_kimi_dev2
2026-09-21 15:58:08 +08:00
parent 47886fed3e
commit 3f46b64218
20 changed files with 377 additions and 38 deletions
@@ -10,7 +10,7 @@
| 端点 | `POST http://<host>:8088/mcp`(MCP Streamable HTTP) |
| 认证 | Header `Authorization: Bearer xqak_xxx`,Token 由管理后台或受信任 Open API 获取;服务端保存 SHA-256 及加密密文 |
| 工具可见性 | `tools/list` 按 ak 作用域过滤,只返回该 ak 作用域并集内且启用状态的工具(2026-09-04 起,服务端 servlet 层重写响应实现);`tools/call` 另有强制校验兜底,越权返回可读拒绝信息并落审计(denied) |
| 行级数据权限 | 跟 ak 所属人走,照搬老系统 `getByIsAgent` 语义(见设计文档 §3.3),与作用域无关 |
| 行级数据权限 | 跟 ak 所属人走,照搬老系统 `getByIsAgent` 语义(见设计文档 §3.3),与作用域无关;**tenant_service 服务主体无用户上下文,按总部视角全量可见**(见 §0.3) |
| 分页 | 列表类工具统一 `page`(从 1 开始,默认 1)、`rows`(默认 20,**上限 100**,超出截断为 100 并在返回 `notice` 字段提示) |
| 分页出参 | 统一含 `total`(总数)、`page`、`rows`、`records`(本页记录)、`notice`(仅截断时出现) |
| 工具声明 | `tools/list` 中每个工具带 MCP annotations:只读(`readOnlyHint=true`)、幂等(`idempotentHint=true`)、非破坏性(`destructiveHint=false`)(REQ-20260911-0011 起) |
@@ -48,6 +48,16 @@
日志与审计不记录 Token/ak,手机号一律脱敏为 `138****5678` 形式。
### 0.3 服务身份(tenant_service)在线查询(REQ-20260921-0004 起)
服务 Token(`principalType=service`,无登录身份)除 SYNC 变化流外,可绑定「允许服务主体」的查询作用域(`agent_scope.service_enabled=1`,如运营用 `ops-query`)调在线查询工具:
- **可见范围**:所有走行级权限的查询工具对服务主体统一按**总部视角全量可见、不做行过滤**(PermissionService 统一分支);用户身份调用行为完全不变。
- **签发**:`POST /api/open/token/ensure` 传 `principalType=service` + `serviceName`,scopeCode 必须是 service_enabled=1 的作用域,否则 403;服务密钥需事先绑定该作用域。
- **限流**:服务主体的在线查询走独立 SERVICE-QUERY 档位(`app.rate-limit.service-query-per-minute`,默认 300/分钟),与用户 QUERY、SYNC 档位互不占配额;调 `*.changes.list` 仍走 SYNC 档。
- **例外**:`warehouse.todo.list.query` 按"当前登录人"统计待办,服务身份无此语义,调用返回 PERMISSION_DENIED,不应绑入服务查询作用域。
- 审计照常落 `audit_log`(token_id + serviceName 可溯源),密钥泄露时在后台单独轮换/吊销。
---
## 1. agent.count