ai_v/services/alipay_service.py
公司git 30105c685a fix(payment): 修复支付宝通知签名验证问题
- 在支付通知日志中添加接收到的支付宝数据记录
- 移除签名验证参数中的 sign_type,避免验证错误
- 优化支付宝服务签名验证逻辑,提高兼容性和准确度
2026-01-23 15:10:16 +08:00

80 lines
3.3 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)
verify_data.pop('sign_type', 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