feat: 平台治理与权限体系完善,存储进度/GPU预留/审批中心与日志整合

- 平台治理: 租户用户权限层次、资源ACL、审批中心与审批模板、访问申请
- 存储: MinIO 存储进度迁移、对象存储安全加固与测试
- 计算: GPU 资源预留、compute 轮询与同步增强
- 权限: permission v2 迁移、权限安全验收测试
- 日志: 后端运行日志中文说明、操作日志整合
- 数据处理/评测: 数据转换与模型评测优化

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
wuyongtao
2026-08-21 09:49:48 +08:00
parent 080ef6ab00
commit 6f0e82f351
94 changed files with 9547 additions and 1045 deletions

View File

@@ -17,6 +17,18 @@ from fastapi import FastAPI, Request
from app.core.config import Settings, get_settings
request_id_var: ContextVar[str] = ContextVar("request_id", default="-")
client_ip_var: ContextVar[str] = ContextVar("client_ip", default="")
def get_client_ip(request: Request | None) -> str:
"""获取客户端地址,兼容前置反向代理传递的真实地址。"""
if request is None:
return ""
for header in ("X-Real-IP", "X-Forwarded-For"):
value = request.headers.get(header, "")
if value:
return value.split(",", 1)[0].strip()
return request.client.host if request.client else ""
# ==================== 敏感数据脱敏规则 ====================
@@ -65,14 +77,21 @@ def mask_sensitive_string(text: str) -> str:
"""从文本中脱敏常见敏感信息"""
if not text:
return text
# Mask the value as well as the key. Replacing only ``api_key=`` would
# still leak the credential in audit messages and exception text.
assignment_pattern = (
r"(Bearer\s+|(?:api[-_]?key|access[_-]?token|refresh[_-]?token|"
r"secret[_-]?key|password|private[_-]?key|token)\s*[:=]\s*)"
r"(\"[^\"]*\"|'[^']*'|[^\s,;]+)"
)
try:
text = re.sub(assignment_pattern, r"\1***", text, flags=re.IGNORECASE)
except re.error:
pass
patterns = [
(r'Bearer\s+[A-Za-z0-9\-._]+', '***'),
(r'token\s*[:=]\s*', '***'),
(r'password\s*[:=]\s*', '***'),
(r'secret[_-]?key\s*[:=]', '***'),
(r'api[-_]?key\s*[:=]', '***'),
(r'private[_-]?key\s*[:=]', '***'),
(r'Bearer\s+[A-Za-z0-9\-._]+', 'Bearer ***'),
(r'\d{11}', r'\d{3}\*\d{4}'), # 手机号/身份证
(r'1[3-9]\d{9}', r'1\*{3}\*{4}'), # 手机号
]
@@ -335,6 +354,7 @@ def setup_request_logging(app: FastAPI) -> None:
async def request_logging_middleware(request: Request, call_next): # type: ignore[no-untyped-def]
request_id = request.headers.get("X-Request-ID") or str(uuid4())
token = request_id_var.set(request_id)
ip_token = client_ip_var.set(get_client_ip(request))
started_at = time.perf_counter()
try:
response = await call_next(request)
@@ -411,6 +431,7 @@ def setup_request_logging(app: FastAPI) -> None:
raise
finally:
request_id_var.reset(token)
client_ip_var.reset(ip_token)
# ==================== 配置函数 ====================