feat: 新增 /admin 只读授权管理后台

- admin.py:HTTP Basic Auth + 服务端渲染单页,概览统计 / 用户与当前授权 /
  最近使用记录 / 会话令牌 / 扫码场景五个区块
- ADMIN_PASSWORD 为空时返回 503 而非放行,避免漏配密码导致全库数据公开
- 不引模板引擎与 CDN,所有入库文本经 html.escape;令牌只显示首尾便于比对
- config.py / .env.example 新增 ADMIN_USER / ADMIN_PASSWORD
- wechat.py 挂载 admin.router;CODEBUDDY.md 补充文档
This commit is contained in:
gjm committed 2026-09-27 20:03:59 +08:00
1 parent 3a8adda365
commit f167550957
5 files changed
+410 -3

No files matched your search

+14 -2
View File
@@ -4,7 +4,7 @@ This file provides guidance to CodeBuddy Code when working with code in this rep
## 项目概述
微信公众号扫码授权服务,基于 FastAPI,为 Windows MFC 桌面程序提供微信扫码授权与使用扣减。已实现微信服务器验证与消息/事件接收(`/wechat`)、扫码授权(`/auth`)、使用扣减(`/usage`)以及首次关注赠送 7 天免费授权。MySQL 已接入(aiomysql 连接池,5 张表);Redis 仅在配置层声明,尚未使用。
微信公众号扫码授权服务,基于 FastAPI,为 Windows MFC 桌面程序提供微信扫码授权与使用扣减。已实现微信服务器验证与消息/事件接收(`/wechat`)、扫码授权(`/auth`)、使用扣减(`/usage`)、只读管理后台(`/admin`)以及首次关注赠送 7 天免费授权。MySQL 已接入(aiomysql 连接池,5 张表);Redis 仅在配置层声明,尚未使用。
## 常用命令
@@ -38,6 +38,7 @@ wechat_api.py # 微信开放接口:access_token 内存缓存 + 临时二维
wechat.py # FastAPI app 本体:lifespan + /wechat 路由 + 签名校验 + XML 解析/构造
auth.py # /auth/* 路由 + 扫码授权业务逻辑(含 pending 激活)
usage.py # /usage/consume 路由:会话校验与使用扣减
admin.py # /admin 只读管理后台:Basic Auth + 服务端渲染 HTML
run_local.py # 开发启动入口(reload=True)
run_server.py # 生产启动入口(reload=False, workers=1)
sql/schema.sql # 建表脚本(5 张表,含索引与外键)
@@ -45,7 +46,7 @@ sql/schema.sql # 建表脚本(5 张表,含索引与外键)
- **配置**:所有敏感值经 `config.py` 从 `.env` 读取,`.env` 已被 `.gitignore` 排除。`.env.example` 是字段模板。新增配置项需同时更新这两处。
- **应用入口**:两个启动脚本均以 `"wechat:app"` 字符串形式加载 `wechat.py` 中的 `app`,因此模块名/对象名不可随意重命名。`lifespan` 在启动时初始化 MySQL 连接池——**MySQL 不可达或库表不存在时应用会直接启动失败**。
- **路由挂载**:`wechat.py` 通过 `include_router` 挂载 `auth.router` 与 `usage.router`。新增 MFC 侧接口应新建独立模块的 router,而不是塞进 `wechat.py`。
- **路由挂载**:`wechat.py` 通过 `include_router` 挂载 `auth.router`、`usage.router` 与 `admin.router`。新增 MFC 侧接口应新建独立模块的 router,而不是塞进 `wechat.py`。
- **微信交互协议**:
- 所有请求先经 `verify_signature()`(token+timestamp+nonce 字典序拼接后 SHA1 比对)校验,失败返回 403。
- GET 校验通过后原样返回 `echostr`。
@@ -63,6 +64,17 @@ sql/schema.sql # 建表脚本(5 张表,含索引与外键)
- **usage_logs**:积分授权每次调用都写(计费凭证);时间授权按 `(user_id, device_id)` 在 `USAGE_LOG_THROTTLE_SECONDS`(默认 60 秒)窗口内节流。
- **失败语义**:`/usage/consume` 一律返回 HTTP 200,用 `{"ok": false, "reason": "expired | exhausted | invalid_token"}` 表达失败。
## 管理后台(/admin)
只读单页,用于查看用户与授权现状:概览统计、用户+当前授权、最近使用记录、会话令牌、扫码场景。
- **鉴权**:HTTP Basic Auth,凭据取自 `.env` 的 `ADMIN_USER` / `ADMIN_PASSWORD`,用 `secrets.compare_digest` 做定时安全比较。
- **`ADMIN_PASSWORD` 为空时 `/admin` 返回 503 而非放行**——不要把它当成可选项,否则等于把全库用户数据公开。
- **只提供 GET**,没有任何写操作(改授权/加积分/封号一律不做)。
- **不引模板引擎**:HTML 由 f-string 拼装,所有入库字段经 `html.escape()`;CSS 内联,不依赖任何 CDN(服务器出网不可靠)。
- 页脚会显示数据库名;页头显示数据生成时间。不做自动刷新。
- `admin.py` 被 `wechat.py` import,因此**不要在 `admin.py` 里反向 import `wechat`**(循环依赖)。
## 数据库
5 张表(定义见 `sql/schema.sql`):`users`、`authorizations`(授权,type 分 time/points)、`auth_scenes`(扫码场景,300 秒一次性)、`usage_logs`(使用日志)、`sessions`(会话令牌)。