updates
This commit is contained in:
parent
052c72eb5a
commit
43561548fd
|
|
@ -29,14 +29,20 @@ async def verify_callback(
|
|||
|
||||
|
||||
@router.post("/webhook")
|
||||
async def receive_callback(request: Request, db: AsyncSession = Depends(get_db)):
|
||||
"""接收消息回调:解密 XML → 拉取消息 → 入库"""
|
||||
async def receive_callback(
|
||||
request: Request,
|
||||
msg_signature: str = Query("", alias="msg_signature"),
|
||||
timestamp: str = Query(""),
|
||||
nonce: str = Query(""),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""接收消息回调:验证签名 → 解密 XML → 拉取消息 → 入库"""
|
||||
try:
|
||||
xml_body = await request.body()
|
||||
xml_str = xml_body.decode("utf-8")
|
||||
logger.info(f"收到回调: {xml_str[:200]}")
|
||||
logger.info(f"收到回调, encrypt 前100字符: {xml_str[:100]}")
|
||||
|
||||
token, open_kfid = decrypt_message(xml_str)
|
||||
token, open_kfid = decrypt_message(xml_str, msg_signature, timestamp, nonce)
|
||||
if not token or not open_kfid:
|
||||
logger.warning("解密后 Token 或 OpenKfId 为空")
|
||||
return PlainTextResponse("fail")
|
||||
|
|
|
|||
|
|
@ -66,22 +66,33 @@ def verify_url(msg_signature: str, timestamp: str, nonce: str, echostr: str) ->
|
|||
return decrypt(echostr)
|
||||
|
||||
|
||||
def decrypt_message(xml_body: str) -> tuple[str, str]:
|
||||
"""POST 请求:解密 XML 消息,返回 (token, open_kfid)
|
||||
def decrypt_message(xml_body: str, msg_signature: str = "",
|
||||
timestamp: str = "", nonce: str = "") -> tuple[str, str]:
|
||||
"""POST 请求:验证签名 + 解密 XML 消息,返回 (token, open_kfid)
|
||||
|
||||
注意:解密后的 XML 包含 <Token> 和 <OpenKfId> 等字段
|
||||
解密后的 XML 包含 <Token> 和 <OpenKfId> 等字段
|
||||
"""
|
||||
root = ET.fromstring(xml_body)
|
||||
encrypt_elem = root.find("Encrypt")
|
||||
if encrypt_elem is None or encrypt_elem.text is None:
|
||||
raise ValueError("XML 中缺少 Encrypt 字段")
|
||||
encrypt_str = encrypt_elem.text
|
||||
|
||||
# 去除可能的空白/换行,确保 Base64 解码正确
|
||||
encrypt_str = encrypt_elem.text.strip()
|
||||
|
||||
# 验证签名(如果提供了签名参数)
|
||||
if msg_signature and timestamp and nonce:
|
||||
if not verify_signature(settings.callback_token, timestamp, nonce,
|
||||
encrypt_str, msg_signature):
|
||||
raise ValueError("消息签名验证失败")
|
||||
|
||||
# 解密
|
||||
plain_text = decrypt(encrypt_str)
|
||||
# 解析解密后的 XML
|
||||
plain_root = ET.fromstring(plain_text)
|
||||
|
||||
# 解密后的内容可能是 XML 或 JSON(取决于微信客服的配置)
|
||||
# 先尝试 XML 解析
|
||||
try:
|
||||
plain_root = ET.fromstring(plain_text)
|
||||
token = ""
|
||||
open_kfid = ""
|
||||
token_elem = plain_root.find("Token")
|
||||
|
|
@ -90,5 +101,11 @@ def decrypt_message(xml_body: str) -> tuple[str, str]:
|
|||
token = token_elem.text or ""
|
||||
if kfid_elem is not None:
|
||||
open_kfid = kfid_elem.text or ""
|
||||
|
||||
return token, open_kfid
|
||||
except ET.ParseError:
|
||||
# 可能是 JSON 格式
|
||||
import json
|
||||
data = json.loads(plain_text)
|
||||
token = data.get("Token", "")
|
||||
open_kfid = data.get("OpenKfId", "")
|
||||
return token, open_kfid
|
||||
|
|
|
|||
Loading…
Reference in New Issue