WIP-CHECKPOINT[auth-refactor]: 固化工程师崩溃前部分成果 + 同树其他未提交WIP(仅源码,不含密钥/二进制)-- 待重激活工程师续作

This commit is contained in:
Simon
2026-07-07 21:52:11 +08:00
parent 242c1967ff
commit fab75760e0
203 changed files with 21504 additions and 3345 deletions
+122 -2
View File
@@ -119,6 +119,18 @@ class Settings(BaseSettings):
# 开发模式默认部门
dev_default_dept: str = "信息技术部"
# ----------------------------------------------------------------------
# 运行环境 & 管理后台 IP 白名单(三端认证重构 AUTH-01)
# ----------------------------------------------------------------------
# 应用运行环境:dev / test / production
# 控制 UA 校验 / IP 白名单 / 真实企微 OAuth 的启用(仅 production 启用)
# 通过环境变量 APP_ENV 控制(默认 dev,避免本地误触发强校验)
app_env: str = "dev"
# 管理后台登录 IP 白名单(逗号分隔,支持 CIDR,如 10.240.0.0/16
# 仅允许白名单内的 IP 访问管理后台登录;其余 IP 返回 4004(无权限)
# 通过环境变量 ADMIN_ALLOWED_IPS 覆盖
admin_allowed_ips: str = "117.147.35.138,218.75.34.87,10.240.0.0/16"
# ----------------------------------------------------------------------
# 审批模板配置(企微审批应用)
# ----------------------------------------------------------------------
@@ -156,6 +168,63 @@ class Settings(BaseSettings):
# 主管接收报警的 userid(多个用逗号分隔)
content_audit_supervisor_userids: str = ""
# ----------------------------------------------------------------------
# 阶段5 自动化闭环配置(环境变量前缀 AUTOMATION_*
# ----------------------------------------------------------------------
# 说明:自动化引擎连接的外部系统基址与密钥占位。
# 优先级:环境变量 AUTOMATION_* > 阶段1-4 既有的 system_configs 集成配置
# huorong/lianruan/ragflow 在 app/integrations/*/config.py 中已有 getter
# 注意:密钥均为占位,生产环境必须通过环境变量注入,切勿硬编码真实密钥。
# ----------------------------------------------------------------------
# Dify(意图识别 / AI 编排)
automation_dify_base_url: str = ""
automation_dify_api_key: str = ""
# RAGFlow(知识库检索,默认内网 :9380)
automation_ragflow_base_url: str = "http://10.80.0.85:9380"
automation_ragflow_api_key: str = ""
# 火绒终端安全(HRESS HMAC-SHA1 签名)
automation_huorong_base_url: str = ""
automation_huorong_access_key_id: str = ""
automation_huorong_access_key_secret: str = ""
# 联软 LV7000(三层认证:IP白名单 + 账号密码 + Token
automation_lianruan_base_url: str = ""
automation_lianruan_api_account: str = ""
automation_lianruan_api_password: str = ""
automation_lianruan_validate_key: str = ""
# 北森 EHR(静态映射兜底)
automation_ehr_base_url: str = ""
automation_ehr_api_key: str = ""
# 自动化阈值(JSON 字符串):置信度下限 / 超时秒 / 连续未解决次数 / 高危必转
# 管理后台可配(见 ScenarioConfig + 全局阈值),此处为默认值。
automation_thresholds: str = '{"confidence_min":0.6,"timeout_seconds":60,"unresolved_threshold":2,"high_risk_force_handoff":true}'
def get_automation_thresholds(self) -> dict:
"""解析自动化阈值配置,返回带默认值的字典。
为什么单独成方法:阈值是 JSON 字符串(便于通过环境变量整体注入),
解析失败时回退到代码内默认值,避免单点配置错误导致引擎不可用。
"""
default = {
"confidence_min": 0.6,
"timeout_seconds": 60,
"unresolved_threshold": 2,
"high_risk_force_handoff": True,
}
try:
import json as _json
if self.automation_thresholds:
parsed = _json.loads(self.automation_thresholds)
if isinstance(parsed, dict):
default.update(parsed)
except Exception as e: # 解析失败仅记日志,不中断启动
logger.warning(f"自动化阈值解析失败,使用默认值: {e}")
return default
# ----------------------------------------------------------------------
# Pydantic-settings 配置
# ----------------------------------------------------------------------
@@ -187,6 +256,9 @@ class Settings(BaseSettings):
def create_redis_client(self) -> aioredis.Redis:
"""创建 Redis 异步客户端实例。
使用单独的 host/port/password 参数,避免 URL 解析问题
(特别是密码中包含特殊字符 ! @ # 时)。
自动附加 protocol=2 参数,强制使用 RESP2 协议。
原因:Windows 版 Redis 3.x 不支持 RESP3 协议(HELLO 命令),
而 redis-py 8.0+ 默认使用 RESP3,会导致连接失败。
@@ -195,9 +267,57 @@ class Settings(BaseSettings):
Returns:
aioredis.Redis: 配置好的 Redis 异步客户端
"""
# 连接超时保护:防止 Redis 不可达时请求无限挂起
# (历史事故:REDIS_URL 密码含 @ # 导致 urlparse 解析到错误 host
# 连接一直挂起,最终表现为登录接口超时 / 502 / 浏览器"网络连接失败")
socket_connect_timeout = 5
socket_timeout = 5
# 如果 redis_url 为空,使用默认值
url = self.redis_url if self.redis_url else "redis://localhost:6379/0"
return aioredis.from_url(url, protocol=2)
if not self.redis_url:
# 默认值:本地 Redis
return aioredis.Redis(
host="localhost",
port=6379,
protocol=2,
decode_responses=True,
socket_connect_timeout=socket_connect_timeout,
socket_timeout=socket_timeout,
)
# 解析 REDIS_URL 提取连接参数
# 格式: redis://:password@host:port/db
# ⚠️ 密码可能含 URL 保留字符(@ # ! 等),部署时必须用 URL-encode:
# @ → %40, # → %23, ! → %21
# 例: R3d!s@2026#Secure → R3d%21s%402026%23Secure
# urlparse 不会自动解码百分号编码,这里用 unquote 还原真实密码/主机
from urllib.parse import urlparse, unquote
parsed = urlparse(self.redis_url)
# 提取密码(先尝试标准 urlparse 字段,失败则从 netloc 兜底)
password = parsed.password
if not password:
# 尝试从 netloc 中提取(格式 :password@host
netloc = parsed.netloc
if "@" in netloc:
password = netloc.split("@")[0].split(":")[-1]
if password:
password = unquote(password)
hostname = unquote(parsed.hostname) if parsed.hostname else "localhost"
port = parsed.port or 6379
db = parsed.path and int(parsed.path.lstrip("/")) or 0
return aioredis.Redis(
host=hostname,
port=port,
password=password,
db=db,
protocol=2,
decode_responses=True,
socket_connect_timeout=socket_connect_timeout,
socket_timeout=socket_timeout,
)
# 创建全局配置实例