Files
DjangoAdmin_FastAPI_EleVue/11.txt
T
ClaudeandClaude dbcce79536 chore: 基线提交(重构前快照)
重构前保存现有 apps/ 结构基线,供后续各阶段回滚。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 09:43:18 +08:00

99 lines
7.5 KiB
Plaintext
Raw 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.
已按企业级标准完成全量审查(约 1.4 万行 Python,覆盖 25 个业务模块 + 核心框架)。以下按严重程度分类汇总。
---
一、严重 BUG(功能已损坏 / 需立即修复)
1. 上传接口全部 500 —— 缺 request 参数
apps/views/upload.py:15/23/31 三个端点签名是 async def upload_image(file: UploadFile = File(...)),没有 Request 参数。而 permission_required 装饰器(apps/middleware/permission_required.py:11-19)靠 _extract_request()
从参数里找 Request,找不到就传 None 进 _check(None) → get_user_id(None) → None.state 抛 AttributeError → 所有用户(含 admin)上传图片/文件都报 500。
▎ 修复:三个函数都补上 request: Request 参数。
2. Excel 导入功能必崩
apps/services/level.py:190:result = await upload.upload_file(...) 返回的是 JSONResponse(R.ok/R.failed),不是 dict,result.get('code') 抛 AttributeError → 500。职级导入完全不可用(全库仅此一处)。
▎ 修复:改为 result.status_code == 200 后 json.loads(result.body),或让 upload.upload_file 返回 dict。
3. 权限字符串系统性不匹配 → 非 admin 用户全部被拒(RBAC 失效)
- 视图层要求:sys:{module}:page(分页)、sys:{module}:batch_delete(批量删除)——见 apps/views/level.py:19/96 及全部模块。
- 权限节点生成器 apps/services/menu.py:244/274 生成的是 sys:{module}:list 和 sys:{module}:dall。
- 种子数据 document/djangoadmin.fastapi.elevue.sql 存的也是 sys:level:list / sys:level:dall。
- 只有 dept 和 menu 视图用 list(与种子一致),其余 20+ 模块全不一致。
结果:非 admin 用户即使在菜单里勾选了"查询",拿到的是 sys:level:list,但 /level/page 端点校验 sys:level:page → 永远"权限不足"。批量删除节点(dall)更是完全无效。
▎ 修复:统一三处(视图、set_permission、种子 SQL)的权限字符串,建议全部收敛为 page / batch_delete。
---
二、高危(安全隐患 / 影响稳定性)
4. 操作日志中间件同步 HTTP 调用阻塞事件循环
apps/middleware/operation_log.py:74-91 在 finally 里直接(未走 to_thread)调用 record_operation_log → utils/ip.py:59 的 get_ip_location 用同步 urllib.request.urlopen(..., timeout=3) 访问
ipapi.co。每次写操作都可能把整个事件循环卡住最长 3 秒,并发下是稳定性隐患。(login_log 在登录服务里已用 asyncio.to_thread 包装,唯独 operation_log 中间件漏了。)
▎ 修复:把 record_operation_log 包进 asyncio.to_thread;或 IP 定位改为异步/本地库。
5. 分页参数非数字 → 500(全模块)
所有 services 都是 int(request.query_params.get("pageNo", 1)),传 ?pageNo=abc 即抛 ValueError。apps/__init__.py 全局异常只处理了 Authorization/Business/RequestValidation 三类,未捕获 ValueError → 裸 500。22
个模块的列表页全中招。
6. 省市区字段 NOT NULL 冲突 → IntegrityError
apps/forms/member.py:16-18、apps/forms/user.py:20-22 的 province_code/city_code/district_code 是 Optional(None),但模型 apps/models/member.py:66-70、user.py:74-78 是 nullable=False。当 city 数组不足 3 个元素时,字段保持 None →
插入/更新抛 IntegrityError → 500。add_user/add_member/update_* 均受影响。
7. 上传大小校验在整文件读入内存之后
apps/services/upload.py:204-208 先 await file.read() 全量读入内存,再比对 UPLOAD_MAX_SIZE_MB。攻击者传超大文件即可耗尽内存(DoS)。应先用 Content-Length 头预检,或流式分段读取。
8. 存储型 XSS 风险
- .svg 在允许列表中,_sanitize_svg 的 apps/services/upload.py:101-128 正则可被绕过(HTML 实体、foreignObject、命名空间等),且无 X-Content-Type-Options: nosniff 保障(若 Nginx 直接服务 uploads/ 目录则风险实锤)。
- apps/services/notice.py:91/122 富文本 content 只转义 title,正文 HTML 原样存储并原样返回(get_notice_detail 第 76 行),无服务端清洗。公告若展示给前台用户即为存储型 XSS。
9. 密钥/配置管理
- .env 未列入 .gitignore(当前项目是 SVN 且 .env 在根目录),内含 DB 密码 root、Redis 密码 123456、JWT 密钥。若入库即泄露。
- .env 中 FASTAPI_UPLOAD_DIR=E:\DjangoAdmin\... 是写死的异机绝对路径(与当前目录 D:\Temp\... 不符);FASTAPI_IMAGE_URL='http://images.fastapi.elevue' 是假域名。FASTAPI_DEBUG=True、DB_DEBUG=True 默认开。
- 本应用没有挂载静态目录(全库无 StaticFiles/mount),上传文件必须靠外部 Nginx 服务,否则返回的 fileUrl 不可访问——部署时需确认。
---
三、中低危 / 优化点
事务与数据一致性
- apps/services/job.py:216/239 在请求内直接 db.commit(),与 db_session_middleware 统一提交重复(冗余);且 pause_job_by_id 里 job.update_user = job.create_user(应为当前操作人 get_user_id(request))。
- update_user_info(apps/services/user.py:312-329)bulk update 不触发 onupdate,update_time/update_user 不会被更新。
性能
- 权限 JOIN(menu.get_permissions_list_sync,apps/services/menu.py:332-345)对 user_role.user_id/role_id、role_menu.menu_id/role_id、menu.parent_id、user.dept_id 等列全无索引,非 admin 每次请求全表扫描。建议加索引。
- perm_cache.invalidate_role_perms(utils/perm_cache.py:117-118)在异步上下文里直接同步 db.query,未走 to_thread。
- 22 个模块的 get_*_page 分页/回退逻辑高度重复,可抽取公共分页组件。
健壮性
- get_access_token(utils/jwt.py:422)replace('Bearer ', '') 大小写敏感,客户端发 bearer 小写会解析失败。
- captcha 防刷 redis.get 后 incr 存在 TOCTOU 竞态(utils/captcha.py:106-130),并发可绕过上限。
- detail 路由 id 为裸字符串(apps/views/level.py:28),未做 int 校验,非法值直接进 SQL。
- base_model.batch_delete_r(apps/models/base_model.py:176)只要有一个 id 不存在就整体报"记录不存在"(all-or-nothing),行为需与前端确认。
- rich_text.save_file(utils/rich_text.py:58-69)对 URL 中的 .. 未规范化,存在目录穿越到上传目录外的可能(需源文件已存在,低危)。
一致性/代码质量
- JobLog 用 del_flag(apps/models/job_log.py:46),其余模型统一 is_delete;create_user/update_user 用 String(50) 而非 Integer。
- forms/dept.py 校验 type 仅 1-2,而模型注释是 1-4。
- config/sms.py 读的 SMS_URL/SMS_API_KEY... 与 .env 中实际变量(SMS_ALIYUN_*)不一致(当前无用,属预留模块)。
- R.ok 允许 kwargs 覆盖 code,可能产生 {"ok": True, "code": 1} 的矛盾响应;R.failed 默认 code=1 与中间件"code==0 即成功"判断需保持口径一致。
- 无测试套件、无 lint/format 配置(CLAUDE.md 已注明),建议至少补 pytest 覆盖鉴权中间件与 CRUD 主路径。
---
四、建议修复优先级
1. 立即:#1 上传 500、#2 Excel 导入 500、#3 权限字符串统一(功能不可用 / RBAC 失效)
2. 尽快:#4 事件循环阻塞、#5 分页 500、#6 NOT NULL 冲突、#7 上传内存 DoS
3. 安全:#8 富文本/SVG XSS、#9 密钥与 DEBUG 配置
4. 后续:#11 索引、#12 公共分页组件、其余一致性项
需要我直接开始修复吗?可以按优先级逐个处理,或先修最严重的 #1–#3(三个都是几行的改动,我可以一次性完成并自测)。