# 登录 Token 鉴权改造存档（2026-09-09）

> 状态：✅ 已实施 + 回归验证通过 | 遗留：CloudBase 权限加固（已设 09-10 22:00 提醒）

## 一、背景与目标

**原问题**：工作台后端所有 `/api/` 端点信任前端传来的 `name`/`role` 明文，攻击者可用 curl 直接伪造 `{name:"刘新元", role:"admin"}` 获得管理员权限（读全量文件、改公共资源）。

**目标**：后端独立验证身份，前端传参不再可信。

## 二、方案

1. **登录发 token**：前端登录成功后调 `/api/auth/token`，后端用 `email+pwd`（或飞书 `open_id`）验证本地用户表，通过则发 `secrets.token_urlsafe(32)` 随机 token。
2. **会话表**：`{token: {name, role, dept, line, email, expire_at}}`，持久化到 `数据/auth_sessions.json`，**7 天滑动续期**（每次鉴权刷新），服务重启不丢。
3. **API 验 token**：`_auth_user()` 读 `Authorization: Bearer <token>` → 查会话表 → 校验过期。`do_GET`/`do_POST` 开头统一鉴权兜底（除 `/api/login`、`/api/auth/token` 外的所有 `/api/` 都需 token）。
4. **role 从后端用户表查**（不可伪造），前端不再决定自己的 role。

## 三、改动清单

**后端 `脚本/销售工作台服务.py`**
- 新增：`AUTH_SESSIONS`/`AUTH_LOCK`/`AUTH_FILE`/`TOKEN_TTL`、`_load_user_roles()`、`_load_sessions()`、`_save_sessions()`、`Handler._auth_user()`
- 新增端点：`/api/auth/token`（email+pwd 或 open_id 验证发 token）
- 统一鉴权兜底：`do_GET`/`do_POST` 开头，所有 `/api/`（除登录/换 token）需 token
- 逐个接入：`/api/chat`、`/api/files/download`、`/api/files/list`、`/api/files/mark_public`、`/api/history`、`/api/token_usage`

**前端 `工具/index.html` + `工具/app.html`（双同步）**
- 新增：`AUTH_TOKEN_KEY`/`AUTH_TOKEN`/`AUTH_APIS`、`fetchAuthToken()`、`apiFetch()`
- `finishLogin`：登录后自动换 token（email+pwd 或 open_id）
- `doLogout`：清 token
- 18 处 `/api/` fetch → `apiFetch`
- iframe 预览：`apiFetch(dlUrl+'&inline=1')` 下载转 `blob:` URL（token 不进 URL，解决 iframe 无法带 header 问题）

**数据 `数据/user_roles.json`**
- 用 `tcb db nosql execute -e bier-sales-d0gatbvlx288724e9` 从 CloudBase `user_roles` 同步的 47 在职用户快照（含 email/pwd/role/line/open_id）

## 四、回归验证（5 项全过）

| 测试 | 结果 |
|---|---|
| 正确凭证换 token | ✅ 200，role=admin 从后端表查得 |
| 伪造 name/role（无 token）调 /api/chat | ✅ 401「登录已过期」 |
| 带 token 调 /api/files/list | ✅ 200 |
| 伪造 admin 调 mark_public（无 token） | ✅ 401 |
| 错误密码换 token | ✅ 401 |

## 五、遗留风险（已设提醒）

CloudBase `user_roles` 集合权限是「所有用户可读」，`pwd` 明文存储 → 理论上匿名登录可读所有人密码，再用密码换 token。**根治待办**：
1. user_roles 权限改「仅创建者可读」/最小化读权限
2. 前端 CloudBase SDK 登录查询 user_roles 改走云函数/服务端查询
3. `/api/auth/token` 的 pwd 验证加服务端密钥或改查云函数

## 六、关键文件

- `脚本/销售工作台服务.py` — 后端主服务（8765）
- `工具/index.html`、`工具/app.html` — 前端（已部署 CloudBase `bier-sales-d0gatbvlx288724e9`）
- `数据/auth_sessions.json` — token 会话表（运行时生成）
- `数据/user_roles.json` — 用户表快照
