# 用 WorkBuddy 把单机 Flask 回收工具,一夜升级成多用户云版(附安全加固实战)
> 标签:#WorkBuddy #Flask #Python #实战教程 #AI协作
## 一、背景:单机版用着憋屈
我做二手电脑/配件回收(傲飞回收),之前用 WorkBuddy 写了一个单机版报价工具 `aofei-recycle-app`:Flask + JSON 存定价、xlsx 存客户和库存。功能能跑,但有个致命问题——**只有我自己的电脑能用**,公司其他人想报个价、录个客户,得凑到我屏幕前。
老板一句话定调:"整理一下,新建一个项目,上线部署,一个账套,公司其他人也能用各自账户登录。"
这就是从 **单机版 → 多用户云版** 的升级。下面把完整过程和踩的坑全部摊开。
---
## 二、架构选型(先拍板再动手)
原版是「无用户、文件存储」。要支持多人在线,核心改三件事:**加数据库、加登录、改部署**。
| 维度 | 旧版 v2.1 | 新版 v3.0 |
|------|-----------|-----------|
| 存储 | JSON + xlsx 散文件 | SQLite 单库(WAL 并发) |
| 用户 | 无,谁开谁用 | 多用户登录,管理员/普通用户分权 |
| 数据 | 散落多文件 | 一个 `aofei.db`,一个账套 |
| 新增 | — | 报价历史、用户管理、操作人追踪 |
技术栈:**Flask + SQLite + 自写 session 认证**。(注:最初列了 Flask-Login,后来评审发现它全程没用到,属于死依赖,直接删了,认证用自写装饰器 `@login_required` / `@admin_required` 更轻。)
---
## 三、实现步骤
### 1. 项目结构
```
aofei-recycle-cloud/
├── app.py # 主程序:所有路由 + 认证 + 权限
├── db.py # SQLite 连接(WAL + busy_timeout)
├── init_db.py # 建表 + 从旧版 JSON/xlsx 迁移数据
├── requirements.txt
├── data/ # aofei.db 存放处
├── uploads/ # OCR 配置表上传目录
└── templates/
├── login.html
├── index.html # 主界面(9 个功能 tab)
└── admin.html # 用户管理页
```
### 2. 数据库设计(核心表)
```sql
-- 用户表(多账户基础)
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT UNIQUE,
password_hash TEXT, -- pbkdf2 哈希
display_name TEXT,
role TEXT DEFAULT 'user', -- admin / user
is_active INTEGER DEFAULT 1
);
-- 定价库(110 条配件,7 大类)
CREATE TABLE pricing (
id INTEGER PRIMARY KEY,
category TEXT, -- CPU/GPU/内存/主板/硬盘/...
name TEXT,
price REAL,
UNIQUE(category, name)
);
-- 客户、库存(入/出)、报价历史 ...
```
`init_db.py` 负责把旧版 110 条定价一次性迁过来,客户/库存旧版是空的就跳过。
### 3. 登录认证(自写 session)
```python
def login_required(f):
@wraps(f)
def wrap(*a, **k):
if "uid" not in session:
return redirect(url_for("login"))
return f(*a, **k)
return wrap
@app.route("/login", methods=["POST"])
def login():
u = query("SELECT * FROM users WHERE username=? AND is_active=1",
(username,), one=True)
if u and verify_password(password, u["password_hash"]):
session["uid"] = u["id"]
session.permanent = True
return redirect(url_for("index"))
return render_template("login.html", error="用户名或密码错误")
```
### 4. 前端迁移:权限门控
普通用户不该看到「新增配件/删除」按钮,用 Jinja2 在服务端直接隐藏入口(后端再兜底校验):
```html
{% if current_user.role == 'admin' %}
<button onclick="showAddPart()">+ 新增配件</button>
{% endif %}
```
### 5. 本地跑通验证
启动服务后,用 curl 跑通核心链路(这是最关键的一步,光看页面不算数):
```bash
# 登录拿 cookie
curl -c c.txt -X POST localhost:5050/login -d "username=admin&password=aofei123"
# 快速报价:i5-12400F + RTX 3060 + 16G,92 折
curl -b c.txt -X POST localhost:5050/api/quote/quick \
-H "Content-Type: application/json" \
-d '{"cpu":"i5-12400F","gpu":"RTX 3060","mem":"16G","discount":0.92}'
# 返回:total=2145, total_with_discount=1973.4 ✅ 匹配准确
```
---
## 四、让 AI 专家团来审代码(WorkBuddy 最香的地方)
功能跑通不等于能上线。我让 WorkBuddy 拉了个**4 人专家团并行评审**(后端 / 前端UX / 部署安全 / 产品测试),每人审不同维度,1 分钟内全部返回。
> 这步强烈推荐:自己写代码容易盲区,让多个 AI 角色从安全、体验、业务角度同时挑刺,比自己复查快 10 倍。
专家团揪出的 **8 个 HIGH 级问题**(不修没法上线):
1. **出库数据迁移 off-by-one**:`range(1,11)` 取索引 0-9 却引用 `row[10]` → 出库记录全丢
2. **OCR 硬编码 Python 路径**:写死开发机路径,换服务器直接挂
3. **存储型 XSS**:转义函数只转了一半,用户输入能注入恶意代码
4. **路径穿越**:文件名用户可控未净化,可读任意文件
5. **SECRET_KEY 硬编码源码**
6. **默认弱口令** admin/aofei123
7. **全站无 CSRF 防护**
8. **定价库普通用户能改价**
---
## 五、安全加固(13 项,全验证通过)
按"不修就没法用"的优先级,把 HIGH 全清,MEDIUM 边用边改:
| 加固项 | 改法 | 验证 |
|--------|------|------|
| CSRF | 自写中间件:`GET /api/csrf` 发 token,写操作校验 `X-CSRF-Token` 头 | 不带 token → 403 |
| 密码哈希 | SHA256 → `werkzeug.pbkdf2`(每用户随机盐),旧账号首次登录自动升级 | hash 前缀变 `pbkdf2:sha256` |
| 定价库权限 | 增/改/删全加 `@admin_required`,前端隐藏入口 | 普通用户改价 → 403 |
| 会话过期 | `PERMANENT_SESSION_LIFETIME = 8h` | — |
| 登录防暴破 | 同账号连错 5 次锁 10 分钟 | — |
| 错误信息 | 4 处不再把 `traceback` 甩给前端 | — |
| 数值校验 | 入库/出库数量>0、金额≥0 | — |
| SQLite | 加 `busy_timeout`,多人并发不锁库 | — |
| 路径穿越 | `secure_filename` + 限 uploads 目录 | `../../etc/passwd` 被净化 |
| XSS | 补全 HTML 转义 | — |
| 死依赖 | 删 Flask-Login | — |
| OCR | 改用 `sys.executable` | 上云不挂 |
| SECRET_KEY | 改环境变量读取 | — |
**关键设计——旧密码平滑升级**:登录时若 `password_hash` 不是 `$pbkdf2$` 前缀,先按旧 SHA256 校验,验证成功后立刻用 bcrypt 覆盖该行。所以默认 admin 第一次登录就自动升级成强哈希,不会卡死你。
---
## 六、成果截图
登录页(多用户入口):

仪表盘(定价库 110 条、客户/库存/报价统计):

定价库(管理员可增改,普通用户只读):

快速报价(谈单神器,输入配置实时算价):

用户管理(管理员建账号、分角色、停用):

---
## 七、下一步:部署上线
功能验证完,准备部署到腾讯云轻量服务器(推荐方案):
- 单机 **2核4G,约 60-90 元/月**,gunicorn + nginx 反代
- nginx 配免费 SSL(Let's Encrypt)强制 HTTPS
- SQLite 每天定时备份
- 当前低频多人场景完全够用,数据量大了再换 PostgreSQL
上线前补三件:HTTPS、默认口令改强、备份脚本。
---
## 八、总结
从「自己电脑上跑」到「公司所有人用各自账号登录」,核心就三步:**换数据库、加登录、加权限**。但真正让它能放心上线的,是**让 AI 专家团审一遍 + 把安全 HIGH 全清**。
整套过程用 WorkBuddy 一个工具搞定:写代码、跑测试、拉专家评审、改 Bug、截图——全在对话里完成。
**复现方式**:工作区 `aofei-recycle-cloud/` 目录即完整项目, `python init_db.py` 初始化,`python app.py` 启动,浏览器开 `localhost:5050`,默认 `admin / aofei123` 登录后去「用户管理」建同事账号即可。
---
*如果这篇对你有帮,点赞收藏;有疑问评论区见。也欢迎分享你用 WorkBuddy 升级老项目的踩坑。*原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。