admin_request_json.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. """运营 Web(/web/admin)JSON 请求体解析。
  2. 与 ApiCryptoMiddleware 配合:中间件未改写 body 时,在路由内解密 `{ enc, ts, nonce, edata }`
  3. 并剥 `{ data: ... }`,避免 FastAPI 声明式 Body 在校验阶段只看到密文信封而 422。
  4. """
  5. from __future__ import annotations
  6. import logging
  7. from typing import Any, Optional, Tuple
  8. from fastapi import Request
  9. from app.core.request_payload import resolve_request_payload
  10. _log = logging.getLogger("sqxp")
  11. async def parse_admin_request_json(
  12. request: Request,
  13. current_user: dict,
  14. *,
  15. source: str,
  16. ) -> Tuple[Any, Optional[str]]:
  17. """
  18. 读取 JSON body;dict 时走 resolve_request_payload(明文 / 密文 / data 包装)。
  19. Returns:
  20. (payload, None) 成功;
  21. (_, err_msg) 密文解密失败(此时 payload 为原始 raw,调用方可忽略)。
  22. """
  23. dw = source.startswith("delivery_warning")
  24. try:
  25. raw: Any = await request.json()
  26. except Exception as ex:
  27. if dw:
  28. _log.warning("parse_admin_request_json source=%s request.json() failed: %s", source, ex)
  29. raw = {}
  30. if isinstance(raw, dict):
  31. if dw:
  32. ed = raw.get("edata")
  33. _log.info(
  34. "parse_admin_request_json source=%s raw_keys=%s enc=%s edata_len=%s user_id=%s",
  35. source,
  36. sorted(raw.keys()),
  37. int(raw.get("enc", 0) or 0),
  38. len(ed) if isinstance(ed, str) else (len(str(ed)) if ed is not None else 0),
  39. current_user.get("user_id"),
  40. )
  41. resolved = resolve_request_payload(raw, current_user, source=source)
  42. if dw:
  43. if isinstance(resolved, dict):
  44. _log.info(
  45. "parse_admin_request_json source=%s resolved_keys=%s",
  46. source,
  47. sorted(resolved.keys()),
  48. )
  49. else:
  50. _log.info(
  51. "parse_admin_request_json source=%s resolved_type=%s",
  52. source,
  53. type(resolved).__name__,
  54. )
  55. if resolved == {} and int(raw.get("enc", 0) or 0) == 1:
  56. if dw:
  57. _log.warning(
  58. "parse_admin_request_json source=%s treating as decrypt failure (resolved empty, enc=1)",
  59. source,
  60. )
  61. return raw, "密文解密失败"
  62. return resolved, None
  63. if dw:
  64. _log.warning(
  65. "parse_admin_request_json source=%s raw_not_dict type=%s",
  66. source,
  67. type(raw).__name__,
  68. )
  69. return raw, None