ai_v/services/alipay_service.py
24024 5dc2fbd0e7 fix(payment): 优化支付回调签名验证逻辑
- 取消支付回调中签名前日志冗余输出,简化验证流程
- verify_notify方法中合并签名和数据为空的校验,减少日志行
- 调整sign和sign_type参数移除逻辑,兼容不同通知类型的签名校验
- 增加验证失败时的详细日志,帮助定位公钥配置问题
- 提示可能公钥使用错误,改善错误排查体验
2026-01-14 19:57:43 +08:00

79 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from alipay import AliPay
from flask import current_app
import os
import logging
logger = logging.getLogger(__name__)
class AlipayService:
def __init__(self):
self.app_id = current_app.config.get('ALIPAY_APP_ID')
self.private_key = current_app.config.get('ALIPAY_APP_PRIVATE_KEY')
self.public_key = current_app.config.get('ALIPAY_PUBLIC_KEY')
self.return_url = current_app.config.get('ALIPAY_RETURN_URL')
self.notify_url = current_app.config.get('ALIPAY_NOTIFY_URL')
self.debug = current_app.config.get('ALIPAY_DEBUG', True)
def get_alipay_client(self):
"""获取支付宝客户端实例"""
return AliPay(
appid=self.app_id,
app_notify_url=self.notify_url,
app_private_key_string=self.private_key,
alipay_public_key_string=self.public_key,
sign_type="RSA2",
debug=self.debug
)
def create_order_url(self, out_trade_no, total_amount, subject):
"""生成支付链接 (电脑网站支付)"""
alipay = self.get_alipay_client()
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=out_trade_no,
total_amount=str(total_amount),
subject=subject,
return_url=self.return_url,
notify_url=self.notify_url
)
# 拼接支付网关 (使用最新的支付宝沙箱域名)
gateway = "https://openapi-sandbox.dl.alipaydev.com/gateway.do" if self.debug else "https://openapi.alipay.com/gateway.do"
return f"{gateway}?{order_string}"
def verify_notify(self, data, signature):
"""验证通知签名"""
try:
if not signature or not data:
logger.error("签名或数据为空")
return False
# 创建数据副本
verify_data = data.copy()
# python-alipay-sdk 的 verify 方法会自动处理 sign 的移除
# 但为了保险,我们手动移除它,保留其他所有字段
verify_data.pop('sign', None)
alipay = self.get_alipay_client()
# 对于同步回调sign_type 实际上是参与签名的(某些版本/接口)
# 对于异步通知sign_type 通常不参与签名
# alipay.verify 会根据情况处理 sign_type
result = alipay.verify(verify_data, signature)
if not result:
logger.error("签名验证失败")
logger.error(f"待验证数据: {verify_data}")
logger.error(f"签名值: {signature}")
logger.error(f"使用的公钥前50位: {self.public_key[:50]}...")
# 检查公钥是否可能是应用公钥而非支付宝公钥
if self.private_key and self.public_key:
logger.warning("提示:如果签名持续验证失败,请确认 ALIPAY_PUBLIC_KEY 是“支付宝公钥”而非“应用公钥”")
else:
logger.info("签名验证成功")
return result
except Exception as e:
logger.error(f"验证签名时发生异常: {str(e)}", exc_info=True)
return False