Files
track-LICA/backend/app/core/config.py
duxingchen f9f3d90f96 fix: 二维码接口去鉴权(修复破图)+ 产品序列号加部门前缀
1) 二维码破图
   /products/qrcode/{sn} 带了 Depends(get_current_user),而前端是用
   <img src="/api/v1/products/qrcode/{sn}"> 引用它的 —— <img> 无法携带
   Authorization 头,请求必然 401,页面上就是破图(同时刷大量 401 审计)。
   该接口不查库、只把调用方传进来的字符串渲染成二维码,没有数据泄露面,
   故去掉鉴权。刻意不做 ?token= 兜底:JWT 进 URL 会渗进访问日志、浏览器
   历史与 Referer,比它想解决的问题更糟。
   实测:HTTP 200 / image/png / 300x300。

2) 序列号部门前缀
   新增 config.SERIAL_PREFIX(LICA 为 "L"),counter_service 生成
   {前缀}{15 位 HEX},总长仍严格 16 位 —— products.serial_number 是
   String(16),前端 TaskTreeViewer / ManualInput / ScanPage 多处按 16 位
   校验,不能改总长。IRIS 实例该值为空串,格式保持原样。
   实测 LICA 生成 L000000000000002。
   前端本就兼容带字母的序列号:TaskTreeViewer 的占位符示例就是
   X20260801000001,ScanPage 的 replace(/[^a-zA-Z0-9]/g,"") 也不会滤掉 L。
2026-09-21 16:34:56 +08:00

70 lines
2.9 KiB
Python
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.

"""核心配置 — Pydantic Settings 自动从 .env 读取"""
import json
from pydantic import model_validator
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# ---- 数据库 ----
DATABASE_URL: str = "postgresql+asyncpg://track:track_prod_2026@localhost:5433/track_production"
# ---- JWT ----
SECRET_KEY: str = "change-me-in-production"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 120 # Access Token: 2 小时
REFRESH_TOKEN_EXPIRE_DAYS: int = 7 # Refresh Token: 7 天
# ---- 调试 ----
DEBUG: bool = True
# ---- 应用元信息 ----
APP_VERSION: str = "1.0.0"
# ---- 日志 ----
LOG_LEVEL: str = "INFO"
LOG_JSON: bool = True # 生产保持 True便于采集本地调试可设 False 换可读格式
# ---- 错误追踪(可选,不装 sentry-sdk 则自动跳过)----
SENTRY_DSN: str | None = None
SENTRY_TRACES_SAMPLE_RATE: float = 0.0
# ---- CORS 跨域白名单JSON 数组字符串,直接从 .env 的 CORS_ORIGINS 读取) ----
CORS_ORIGINS: str = '["http://localhost:1420", "tauri://localhost"]'
# ---- MOM 仓储系统回调 WebhookTrack 作为接收方,验签用) ----
TRACK_WEBHOOK_KEY: str | None = None # MOM 回调 POST 时 Header X-API-Key 须等于此值
# ---- 组织隔离 ----
# 同一套代码部署给不同部门时,只需改这两个值(+ compose 里的项目名/容器名/端口)。
# 全仓库的部门过滤点只有三处 SQL登录、人员列表、物料选择器全部引用这里。
ORG_DEPARTMENT: str = "LICA" # MOM sys_user.department 的取值
MATERIAL_CATEGORY_PREFIX: str = "LICA/" # MOM material_base.category 的部门前缀
# 产品序列号前缀(产品身份证 / 二维码内容)。留空则生成纯 16 位 HEX。
# LICA 用 "L" 打头一眼区分部门来源IRIS 实例保持空串不受影响。
SERIAL_PREFIX: str = "L"
@property
def CORS_ORIGINS_LIST(self) -> list[str]:
"""将 JSON 字符串解析为 Python list供 CORSMiddleware 使用"""
try:
return json.loads(self.CORS_ORIGINS)
except (json.JSONDecodeError, TypeError):
return ["http://localhost:1420", "tauri://localhost"]
@model_validator(mode="after")
def _validate_production_secret(self):
"""生产环境强制校验SECRET_KEY 禁止使用默认值"""
if not self.DEBUG and self.SECRET_KEY == "change-me-in-production":
raise ValueError(
"生产环境 (DEBUG=False) 禁止使用默认 SECRET_KEY。"
"请在 .env 中设置 SECRET_KEY 为至少 32 字符的随机值。"
"示例: python -c \"import secrets; print(secrets.token_urlsafe(32))\""
)
return self
class Config:
env_file = ".env"
extra = "ignore"
settings = Settings()