This commit is contained in:
2026-06-15 09:30:25 +08:00
parent 5faf42b451
commit 5a86350829
+35 -21
View File
@@ -105,17 +105,18 @@ async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)):
logger.exception(f"Mock WeChat callback error: {e}")
return {"code": "SUCCESS", "message": "OK"} # 微信要求即使处理失败也返回成功
# 真实模式:使用 wechatpayv3 SDK 验证回调并解析数据
# 真实模式:使用 wechatpayv3 SDK 工具验证回调并解析数据
try:
from wechatpayv3 import Sign, AesCrypto
from wechatpayv3.utils import (
rsa_verify, load_public_key, sha256, b64decode,
AESGCM, InvalidTag
)
mch_id = db_configs.get("payment_wechat_mch_id", "")
private_key = db_configs.get("payment_wechat_private_key", "")
cert_serial_no = db_configs.get("payment_wechat_cert_serial_no", "")
api_v3_key = db_configs.get("payment_wechat_api_v3_key", "")
public_key = db_configs.get("payment_wechat_public_key", "")
if not all([mch_id, private_key, cert_serial_no, api_v3_key]):
if not all([mch_id, api_v3_key]):
logger.error("WeChat payment config missing for callback")
return {"code": "SUCCESS", "message": "OK"}
@@ -124,25 +125,28 @@ async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)):
timestamp = headers.get("Wechatpay-Timestamp", "")
nonce = headers.get("Wechatpay-Nonce", "")
signature = headers.get("Wechatpay-Signature", "")
serial_no = headers.get("Wechatpay-Serial", "")
# 验证签名:使用平台公钥验证
if not public_key:
logger.warning("WeChat platform public key not configured, skipping signature verification")
else:
is_verified = Sign.verify(
public_key=public_key,
timestamp=timestamp,
nonce=nonce,
body=body_str,
signature=signature
)
if not is_verified:
logger.warning("WeChat callback signature verification failed")
if public_key:
try:
# 构造签名串
sign_string = f"{timestamp}\n{nonce}\n{body_str}\n"
# 验证签名
is_verified = rsa_verify(
public_key=load_public_key(public_key),
data=sign_string.encode('utf-8'),
signature=b64decode(signature)
)
if not is_verified:
logger.warning("WeChat callback signature verification failed")
raise HTTPException(status_code=400, detail="签名验证失败")
except Exception as e:
logger.warning(f"WeChat signature verification error: {e}")
raise HTTPException(status_code=400, detail="签名验证失败")
else:
logger.warning("WeChat platform public key not configured, skipping signature verification")
# 解密回调数据:使用 API v3 key
crypto = AesCrypto(api_v3_key)
import json
body_data = json.loads(body_str) if body_str else {}
resource = body_data.get("resource", {})
@@ -155,9 +159,19 @@ async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)):
associated_data = resource.get("associated_data", "")
nonce_str = resource.get("nonce", "")
decrypted_str = crypto.decrypt_gcm(ciphertext, associated_data, nonce_str)
# 使用 AES-GCM 解密
try:
aesgcm = AESGCM(api_v3_key)
decrypted_str = aesgcm.decrypt(ciphertext, associated_data, nonce_str)
except InvalidTag:
logger.error("WeChat callback decryption failed: Invalid tag")
raise HTTPException(status_code=400, detail="数据解密失败")
except Exception as e:
logger.error(f"WeChat callback decryption failed: {e}")
raise HTTPException(status_code=400, detail="数据解密失败")
if not decrypted_str:
logger.error("WeChat callback decryption failed")
logger.error("WeChat callback decryption returned empty")
raise HTTPException(status_code=400, detail="数据解密失败")
decrypted_data = json.loads(decrypted_str)