baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
"""请求上下文透传(迭代第 3 轮)。
**问题**:审计需要 IP / User-Agent,但业务服务层(`sales.services.confirm_sales_bill` 等)
拿不到 `request` 对象——它们是被视图调用的纯函数,签名里加 request 会污染业务 API。
**方案**:中间件在请求进入时把 request 存进 `contextvars.ContextVar`,
服务层通过 `current_request()` 读取。用 contextvars 而非 threading.local 是为了
在 ASGI(Graniot/asyncio)下也能正确隔离协程——threading.local 在异步场景会串请求。
安全性:只读用途(审计取 IP/UA),不做鉴权决策;请求结束即清除。
"""
from __future__ import annotations
from contextvars import ContextVar
from typing import Optional
_current_request: ContextVar[Optional[object]] = ContextVar(
"dealerhub_current_request", default=None
)
def set_current_request(request) -> None:
"""中间件调用:绑定当前请求。"""
_current_request.set(request)
def clear_current_request() -> None:
"""中间件调用:解绑(防止跨请求泄漏)。"""
_current_request.set(None)
def current_request():
"""服务层调用:取当前请求(可能为 None,如后台任务/测试)。"""
return _current_request.get()
class RequestContextMiddleware:
"""把 request 放进 contextvar,供服务层读取(审计用)。
注意:本中间件**不**做鉴权或租户解析(那些由 TenantMiddleware / DRF 负责),
仅提供"当前请求"的只读视图。
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
token = _current_request.set(request)
try:
return self.get_response(request)
finally:
# 用 reset 精确恢复到进入前的值,避免异步并发下互相覆盖
_current_request.reset(token)