Files
server-core/README.md
T

156 lines
6.4 KiB
Markdown
Raw Normal View History

# 云超服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/`