--- title: SaaS 平台 updated: 2026-04-21 status: active tags: [module, saas, auth, billing] --- # SaaS 平台 > 从 [[index]] 导航。关联模块: [[routing]] [[chat]] ## 设计思想 **核心定位: SaaS 是 Tauri 桌面端的中枢,不是独立 Web 应用。** 关键决策: 1. **Token Pool** — 桌面端不持有 LLM API Key,SaaS 维护共享 Key 池,RPM/TPM 轮换 2. **JWT + Cookie 双通道** — Tauri 用 OS keyring 存 JWT,浏览器用 HttpOnly cookie 3. **计费闭环** — 配额实时递增 → 聚合器调度 → mock 支付路由 4. **Admin V2** — 17 页管理后台,管理模型/用户/计费/知识库 ## 功能清单 | 功能 | 描述 | 入口文件 | 状态 | |------|------|----------|------| | 用户认证 | 注册/登录/JWT刷新/登出 | auth/handlers.rs | ✅ | | TOTP 2FA | 设置/验证/禁用 | auth/handlers.rs | ✅ | | Token Pool | RPM/TPM 轮换 Key 分配 | relay/handlers.rs | ✅ | | 聊天中转 | OpenAI 兼容 relay | relay/handlers.rs | ✅ | | 计费系统 | 配额递增/订阅/支付回调 | billing/ | ✅ | | 用户管理 | CRUD/状态/设备/token | account/ | ✅ | | 模型管理 | Provider/模型/Key CRUD | model_config/ | ✅ | | Agent 模板 | 模板 CRUD + 自动分配 | agent_template/ | ✅ | | 知识库 | 分类/条目/搜索/pgvector | knowledge/ | ✅ | | Prompt 管理 | 版本控制/回滚 | prompt/ | ✅ | | 角色权限 | RBAC + 权限模板 | role/ | ✅ | | 行业配置 | 行业 CRUD + 账户分配 | industry/ | ✅ | | 定时任务 | 任务调度 CRUD | scheduled_task/ | ✅ | | 用量统计 | Telemetry 上报/查询 | telemetry/ | ✅ | | 配置同步 | 项 CRUD/分析/seed/sync/diff | migration/ | ✅ | | Admin Dashboard | 系统概览 + 运营指标 | account/admin_routes | ✅ | | Mock 支付 | 开发环境模拟支付 | billing/mock_routes | ✅ | ## 代码逻辑 ### 认证流 ``` 用户登录 (POST /api/v1/auth/login) → Argon2id + OsRg 盐验证密码 → 签发 JWT (Claims: user_id, role, pwv) → set_auth_cookies(): zclaw_access_token (path:/api, 2h TTL, HttpOnly) zclaw_refresh_token (path:/api/v1/auth, 7d TTL, HttpOnly) Secure: dev=false, prod=true | SameSite=Strict 前端存储: → Tauri: OS keyring → saasStore.token → 浏览器: HttpOnly Cookie (JS 不可读) → localStorage: saasUrl + account 信息 (非敏感) ``` ### Token 池 + 限流 ``` SaaS Relay 收到 LLM 请求 (POST /api/v1/relay/chat/completions) → 验证 JWT → 提取 user_id → 从 Token Pool 选择可用 Key (RPM/TPM 轮换) → 转发请求到真实 LLM API → 记录 usage (record_usage worker) → 返回响应 限流规则: → /api/auth/login: 5次/分钟/IP (防暴力) + 持久化到 PostgreSQL → /api/auth/register: 3次/小时/IP (防刷注册) → 公共端点: 20次/分钟/IP ``` ### 密码安全 ``` JWT password_version (pwv): → JWT Claims 含 pwv 字段 → 每次验证 JWT 时比对 Claims.pwv vs DB.pwv → 修改密码 → DB.pwv 递增 → 所有旧 JWT 自动失效 密码存储: Argon2id + OsRg 随机盐 TOTP 加密: AES-256-GCM + 随机 Nonce ``` ### Token 刷新 ``` POST /api/v1/auth/refresh → 验证 refresh_token (单次使用) → 旧 refresh_token 撤销到 DB (rotation 校验) → 签发新 access + refresh token ``` ### SaaS 模块结构(代码验证) 16 个模块目录 (`crates/zclaw-saas/src/`): ``` account/ agent_template/ auth/ billing/ industry/ knowledge/ migration/ model_config/ models/ prompt/ relay/ role/ scheduled_task/ tasks/ telemetry/ workers/ ``` ### SaaS API 分布 137 个 `.route()` 调用,13 个路由模块 (main.rs `.merge()` 注册)。 | 模块 | 路由注册 | 说明 | |------|----------|------| | auth | handlers.rs | 登录/注册/刷新/2FA | | relay | relay/ | 聊天中转/模型列表/任务 | | billing | billing/ + callback_routes | 配额/订阅/支付 | | knowledge | knowledge/ | 知识库 CRUD + pgvector (最大模块) | | model_config | model_config/ | Provider + 模型管理 | | account | account/ | 用户管理 | | agent_template | agent_template/ | Agent 模板 | | role | role/ | 角色 + 权限 | | telemetry | telemetry/ | 用量统计 | | prompt | prompt/ | Prompt 模板 | | scheduled_task | scheduled_task/ | 定时任务 CRUD | | industry | industry/ | 行业配置管理 (V13 新增) | | migration | migration/ | Schema 迁移 | ### 数据表 (42 CREATE TABLE) 38 个 SQL 迁移文件 (21 up + 17 down),42 个 `CREATE TABLE` 语句。 核心表: users, agents, conversations, messages, billing_*, knowledge_*, model_configs, roles, permissions, scheduled_tasks, telemetry, agent_templates, saas_schema_version, user_profiles, trajectory_records, industries, account_industries ### Workers (7 个) | Worker | 文件 | 职责 | |--------|------|------| | log_operation | workers/ | 操作日志 | | cleanup_rate_limit | workers/ | 限流记录清理 | | cleanup_refresh_tokens | workers/ | 刷新 token 清理 | | record_usage | workers/ | 用量记录 | | update_last_used | workers/ | 模型最后使用更新 | | aggregate_usage | workers/ | 用量聚合 | | generate_embedding | workers/ | 内容分块 (embedding deferred) | ## API 接口 ~118 个唯一路由,分布在 13 个模块中(详见上方「SaaS API 分布」和各模块 `mod.rs`)。 | 模块 | 路由数 | 核心端点 | |------|--------|---------| | auth | 9 | POST /auth/{register,login,refresh,logout} + TOTP + password | | relay | 5 | POST /relay/chat/completions + GET /relay/models | | billing | 12 | 订阅/用量/支付/mock/回调/invoice | | knowledge | 24 | 分类/条目/搜索/上传/版本/分析/结构化 | | model_config | 19 | Provider/模型/Key/模型组/用量 | | account | 12 | CRUD/状态/token/设备/操作日志/dashboard | | agent_template | 11 | 模板 CRUD + 创建 Agent + 分配 | | industry | 8 | 行业 CRUD + 账户分配 | | prompt | 6 | Prompt CRUD + 版本/回滚 | | role | 6 | 角色/权限模板 CRUD | | telemetry | 4 | 上报/统计/日报/审计 | | scheduled_task | 2 | 定时任务 CRUD | | migration | 8 | 配置项 CRUD + 分析/seed/sync/diff | ## 测试链路 | 功能 | 测试文件 | 说明 | |------|---------|------| | 认证 | `crates/zclaw-saas/tests/auth_test.rs` | 注册/登录/刷新/登出 | | 认证安全 | `crates/zclaw-saas/tests/auth_security_test.rs` | 安全边界场景 | | 账户 | `crates/zclaw-saas/tests/account_test.rs` | CRUD/token/设备 | | 账户安全 | `crates/zclaw-saas/tests/account_security_test.rs` | 安全边界 | | Agent 模板 | `crates/zclaw-saas/tests/agent_template_test.rs` | 模板 CRUD | | 计费 | `crates/zclaw-saas/tests/billing_test.rs` | 计划/订阅/支付 | | 知识库 | `crates/zclaw-saas/tests/knowledge_test.rs` | CRUD/搜索 | | 模型配置 | `crates/zclaw-saas/tests/model_config_test.rs` | Provider/模型/Key | | 模型配置扩展 | `crates/zclaw-saas/tests/model_config_extended_test.rs` | 扩展覆盖 | | Prompt | `crates/zclaw-saas/tests/prompt_test.rs` | 版本管理 | | 权限矩阵 | `crates/zclaw-saas/tests/permission_matrix_test.rs` | 角色/权限 | | Relay | `crates/zclaw-saas/tests/relay_test.rs` | 聊天中转 | | Relay 验证 | `crates/zclaw-saas/tests/relay_validation_test.rs` | 请求验证 | | 角色 | `crates/zclaw-saas/tests/role_test.rs` | 角色 CRUD | | 定时任务 | `crates/zclaw-saas/tests/scheduled_task_test.rs` | 任务 CRUD | | Telemetry | `crates/zclaw-saas/tests/telemetry_test.rs` | 上报/查询 | | 配置同步 | `crates/zclaw-saas/tests/migration_test.rs` | sync/diff/seed | | Admin 启动 | `crates/zclaw-saas/tests/smoke_saas.rs` | 启动冒烟 | | Admin V2 UI | `admin-v2/tests/pages/*.test.tsx` (17文件) | 每页独立测试 | | 桌面端 SaaS | `tests/desktop/connectionStore.adminRouting.test.ts` | Admin 路由 | | 桌面端集成 | `tests/desktop/integration/zclaw-api.test.ts` | API 集成 | ## 关联模块 - [[routing]] — SaaS Relay 是 Tauri 的主路径 - [[chat]] — 聊天请求经过 SaaS relay 中转 - [[memory]] — knowledge_chunks 表有 pgvector 索引 ## 关键文件 | 文件 | 职责 | |------|------| | `crates/zclaw-saas/src/main.rs` | 路由注册入口 (13个 .merge()) | | `crates/zclaw-saas/src/auth/handlers.rs` | 认证端点 | | `crates/zclaw-saas/src/relay/` | 聊天中转 | | `crates/zclaw-saas/src/billing/` | 计费 | | `crates/zclaw-saas/src/knowledge/` | 知识库 | | `crates/zclaw-saas/src/workers/` | 7 个后台 Worker | | `crates/zclaw-saas/migrations/` | SQL 迁移 (38 文件) | | `admin-v2/src/pages/` | 17 页管理后台(含 Dashboard/Accounts/Billing/Industries/Knowledge/Prompts/Roles/ScheduledTasks/Config 等) | | `desktop/src/lib/saas-client.ts` | 前端 SaaS API 客户端 | | `desktop/src/store/saasStore.ts` | SaaS 认证状态 | ## 安全 完整审计: `docs/features/SECURITY_PENETRATION_TEST_V1.md` - CORS 白名单 (生产缺失拒绝启动) - Cookie Secure (dev=false, prod=true) - JWT 签名密钥 >= 32 字符 (release fallback 拒绝启动) - 独立 TOTP 加密密钥 ## 已知问题 - ⚠️ **Admin 用量统计显示 0/0** — P2 Open。Dashboard 显示 17 requests / 6304 tokens,但 Usage 页显示 0/0,数据源不一致 - ⚠️ **SaaS Embedding 生成未实现** — Open。pgvector 索引就绪,`generate_embedding.rs` Worker 存在但生成逻辑未实现 - ⚠️ **AuthGuard 竞态条件** — P1-04 Deferred。并发请求时可能绕过认证 - ✅ **Dashboard 404** — BUG-H1 已修复。`/api/v1/admin/dashboard` 路由注册遗漏 - ✅ **invoice_id 未暴露** — BUG-M1 已修复 - ✅ **非 Admin 返回 404 而非 403** — BUG-M4 已修复 (admin_guard_middleware)