Files

156 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 云超服Agents 演示后端(pineagents-demo-server
**PineAgents** 主后端认证转发的演示 FastAPI。主后端 `src/pineagents/app/routers/auth.py`
把所有 `/api/auth/*` 请求转发到本服务(`PINEAGENTS_DEMO_BASE_URL`,默认 `http://127.0.0.1:8090`),
本服务只负责登录、注册、资料维护等演示接口。
- **框架**FastAPI + uvicorn,环境由 [uv](https://docs.astral.sh/uv/) 管理
- **数据**:本地 JSON 文件(`data/` 目录),首次启动从 `data/seed/` 种子数据初始化
- **演示账号**`pine` / `123456`
- **下阶段**:依据 JSON 文件的结构(见下文「JSON 格式与未来数据库映射」)设计并替换为真实数据库
---
## 快速开始
```bash
# 1. 安装依赖(首次)
uv sync
# 2. 启动服务(默认 127.0.0.1:8090
uv run uvicorn app.main:app --host 127.0.0.1 --port 8090 --reload
# 或
uv run python -m app
# 3. 运行测试
uv run pytest
```
启动后接口文档:<http://127.0.0.1:8090/docs>
## 目录结构
```
PineAgentsServer/
├── pyproject.toml # uv 项目配置(依赖、构建、pytest)
├── app/
│ ├── main.py # FastAPI 应用入口(lifespan 初始化 JSON 数据库)
│ ├── config.py # 端口 / 数据目录 / 令牌有效期等配置
│ ├── models.py # Pydantic 请求/响应模型(与主后端转发模型一致)
│ ├── security.py # 密码哈希(加盐 SHA-256)与令牌生成
│ ├── storage.py # JSON 存储引擎:一个文件 = 一张表
│ ├── repositories.py # 数据访问层:UserRepository / TokenRepository / Database
│ ├── dependencies.py # get_db / get_current_userBearer 校验)
│ └── routers/auth.py # /auth/* 路由
├── data/
│ ├── seed/demo_users.json # 种子数据(提交到仓库)
│ ├── users.json # 运行时生成(已 gitignore,等同数据库文件)
│ └── tokens.json # 运行时生成(已 gitignore
└── tests/test_auth.py # 接口端到端测试
```
## 接口一览
| 方法 | 路径 | 说明 | 鉴权 |
| --- | --- | --- | --- |
| POST | `/auth/login` | 登录,成功返回令牌 + 资料 | 否 |
| POST | `/auth/register` | 注册唯一账户(演示端已有用户 → 403) | 否 |
| GET | `/auth/status` | 认证开关 / 是否已有用户 | 否 |
| GET | `/auth/verify` | 校验 Bearer 令牌 → `{valid, username}` | 否(无效返回 401 |
| GET | `/auth/me` | 当前用户完整资料 | Bearer |
| POST | `/auth/update-profile` | 更新资料 / 用户名 / 密码,返回最新资料 | Bearer |
| POST | `/auth/revoke-token` | 吊销单个令牌(省略则吊销当前) | Bearer |
| POST | `/auth/revoke-all-tokens` | 吊销全部令牌 | Bearer |
| GET | `/health` | 健康检查 | 否 |
`update-profile` 规则:
- 仅改资料字段(`nickname/account/company/room/avatar/company_avatar`)时无需密码、不重签令牌;
- 修改用户名/密码时必须提供正确的 `current_password`,成功后吊销该用户其余会话并重签令牌随响应返回;
-`new_username`/`new_password` → 400;没有任何可更新内容 → 400 "Nothing to update"
- 当前密码错误 → 401 "Current password is incorrect"。
## JSON 格式与未来数据库映射
> 设计原则:**文件名 = 表名,数组元素 = 一行,字段 = 一列**。下阶段把
> `storage.py` + `repositories.py` 换成 SQL/ORM 实现即可,路由与业务逻辑不变。
### `data/users.json`(用户表)
首次启动由 `data/seed/demo_users.json` 生成:种子里只有明文 `password`
初始化时立即哈希并落盘为 `password_hash` + `password_salt`,磁盘上不保留明文。
```json
[
{
"id": "u_demo_01",
"username": "pine",
"password_hash": "cf6238f4...d854ed7",
"password_salt": "e23eee00389d5954a88fcd21cef9176f",
"nickname": "云超服小助手",
"account": "云超服演示账号",
"company": "云超服科技",
"room": "1001",
"avatar": "",
"company_avatar": "",
"created_at": "2026-08-02T12:42:36+00:00",
"updated_at": "2026-08-02T12:42:36+00:00"
}
]
```
| JSON 字段 | 未来数据库列 | 类型(建议) | 说明 |
| --- | --- | --- | --- |
| `id` | `id` | `TEXT PK` | 用户主键 |
| `username` | `username` | `TEXT UNIQUE NOT NULL` | 登录名 |
| `password_hash` | `password_hash` | `TEXT NOT NULL` | 密码哈希 |
| `password_salt` | `password_salt` | `TEXT NOT NULL` | 密码盐 |
| `nickname/account/company/room/avatar/company_avatar` | 同名列 | `TEXT DEFAULT ''` | 演示资料字段 |
| `created_at / updated_at` | 同名列 | `TIMESTAMPTZ NOT NULL` | 时间戳 |
### `data/tokens.json`(访问令牌/会话表)
```json
[
{
"id": "tok_46388dab7a5333ff6c8a5a7f",
"token": "01Sek11n8G...Intk",
"user_id": "u_demo_01",
"username": "pine",
"created_at": "2026-08-02T12:42:39+00:00",
"expires_at": "2026-08-09T12:42:39+00:00",
"revoked": false
}
]
```
| JSON 字段 | 未来数据库列 | 类型(建议) | 说明 |
| --- | --- | --- | --- |
| `id` | `id` | `TEXT PK` | 令牌记录主键 |
| `token` | `token` | `TEXT UNIQUE NOT NULL` | 不透明令牌串 |
| `user_id` | `user_id` | `TEXT FK → users.id` | 所属用户 |
| `username` | `username` | `TEXT` | 冗余用户名(便于查询/展示) |
| `created_at` | `created_at` | `TIMESTAMPTZ NOT NULL` | 签发时间 |
| `expires_at` | `expires_at` | `TIMESTAMPTZ NOT NULL` | 过期时间(`-1/0` = 永久 ≈ 100 年) |
| `revoked` | `revoked` | `BOOLEAN DEFAULT FALSE` | 是否已吊销 |
## 配置项(环境变量)
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `PINEAGENTS_DEMO_HOST` | `127.0.0.1` | 监听地址 |
| `PINEAGENTS_DEMO_PORT` | `8090` | 监听端口(与主后端 `DEMO_API_BASE_URL` 一致) |
| `PINEAGENTS_DEMO_DATA_DIR` | `<项目根>/data` | JSON 数据目录 |
| `PINEAGENTS_DEMO_AUTH_ENABLED` | `true` | 认证开关(`true/1/yes` |
## 与本项目(PineAgents)的对接
主后端已把 `/api/auth/login|register|status|verify|me|update-profile|revoke-token|revoke-all-tokens`
转发到本服务。联调时:
1. 本服务监听 `127.0.0.1:8090`
2. 主后端 `constant.py``DEMO_API_BASE_URL` 指向它(或设 `PINEAGENTS_DEMO_BASE_URL`);
3. 前端用 `pine / 123456` 登录即可。
测试(`tests/test_auth.py`)使用临时目录的 JSON 数据库,不会污染 `data/`