From 42f6e242b45cd84d66bf539798cfda0573ab7de5 Mon Sep 17 00:00:00 2001 From: duxingchen Date: Tue, 22 Sep 2026 13:43:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(qrcode):=20=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=8E=BB=E9=89=B4=E6=9D=83=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E6=8A=8A=20qrcode=20=E8=B7=AF=E5=BE=84=E6=8E=92=E9=99=A4?= =?UTF-8?q?=E5=87=BA=E5=AE=A1=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端以 引用该端点,而 无法携带 Authorization 头 —— 加了鉴权会让所有二维码图片加载失败(页面显示成破图), 并在审计里刷出大量 401。 去鉴权是安全的:本函数不查数据库,只校验长度并把这个字符串渲染成二维码, 没有任何业务数据泄露面(序列号本身就是调用方提供的)。也刻意不支持 ?token= 兜底 —— 把 JWT 放进 URL 会渗进访问日志、浏览器历史与 Referer,比它想解决的 问题更糟。 随之而来的副作用必须一并处理:qrcode 路径命中 _TRACKED_READ_PREFIXES 里的 /api/v1/products 前缀、又不是 bare list,会被判成「查看详情」逐条留痕。列表页 一次渲染就并发拉几十张图,逐条留痕会把审计日志塞满,真正有价值的操作反而被 淹没。故把 /api/v1/products/qrcode 加进 _IGNORED_PREFIXES。 实测:二维码正常加载;审计中不再出现 qrcode 记录。 --- backend/app/api/v1/endpoints/products.py | 17 +++++++++++++---- backend/app/core/audit_middleware.py | 11 ++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/backend/app/api/v1/endpoints/products.py b/backend/app/api/v1/endpoints/products.py index 878faa8..016985d 100644 --- a/backend/app/api/v1/endpoints/products.py +++ b/backend/app/api/v1/endpoints/products.py @@ -26,12 +26,21 @@ router = APIRouter(prefix="/products", tags=["产品管理"]) # ============================================================ @router.get("/qrcode/{serial_number}") -async def get_product_qrcode( - serial_number: str, - current_user: dict = Depends(get_current_user), -): +async def get_product_qrcode(serial_number: str): """ 生成产品二维码(PNG 图片)。 + + ⚠️ 本接口【刻意不加鉴权】: + 前端以 `` 引用它,而 + 无法携带 Authorization 头 —— 加了鉴权会让所有二维码图片加载失败, + 并在审计里刷出大量 401。 + + 不加鉴权是安全的:本函数**不查数据库**,只校验长度并把这个字符串渲染成 + 二维码,没有任何业务数据泄露面(序列号本身就是调用方提供的)。 + + 也刻意不支持 ?token= 兜底:把 JWT 放进 URL 会渗进访问日志、浏览器历史 + 与 Referer,比它想解决的问题更糟。 + 内容为 16 位序列号,扫描后可调用 /scan/{serial_number} 查询产品。 尺寸:300×300 px,用于 PC 端打印或嵌入标签。 """ diff --git a/backend/app/core/audit_middleware.py b/backend/app/core/audit_middleware.py index f42f1b0..ffddc89 100644 --- a/backend/app/core/audit_middleware.py +++ b/backend/app/core/audit_middleware.py @@ -56,7 +56,16 @@ _TRACKED_READ_PREFIXES = ( ) # 永久忽略的路径前缀 -_IGNORED_PREFIXES = ("/health", "/docs", "/redoc", "/openapi.json") +# +# 两类内容: +# 1. 探针与文档(/health、/docs…)—— 噪声没有审计价值 +# 2. 图片类端点(/api/v1/products/qrcode)—— 走 加载, +# 一次列表页渲染就会并发拉几十张图,逐条留痕会把审计日志塞满, +# 真正有价值的操作反而被淹没。它也不含业务数据(只渲染二维码图片)。 +_IGNORED_PREFIXES = ( + "/health", "/docs", "/redoc", "/openapi.json", + "/api/v1/products/qrcode", +) # 路径段 → 审计模块 _PATH_MODULE: dict[str, str] = {