[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决 
                                                    
                        
                    
                    
  
                    
                    [fastadmin] 第三十九篇 FastAdmin easypay yansonga 支付宝支付 回调 验签名错误 bug解决
错误演示
- 配置好pay之后,支付都是好的
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/tKtbcxr9m4.png!large)
- 但是支付宝付款 回调 进行代码打印输出,发现是验签错误
一般这里是走的是v2,v3最新的,但是包肯定没普及那么多。要知道还有很多得支付,使用商户pid,以及key进行发起的呢?这种都是2007 时候常用的支付代码了。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/Dg6dY7rmxz.png!large)
点进去 verify
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/kOTWRNykHq.png!large)
再点进去 support类
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/tDHxho2Jep.png!large)
找到最终执行代码地方
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/RkiA7lH1wA.png!large)
3.验签错误,进行支付宝开放平台密钥工具,验签。
得到params 参数,注意这里参数,你可以通过 支付宝,查询trade_no,进行查询 人家发送给你的回调通知。
地址在这:
验签工具:opensupport.alipay.com/support/FAQ...
- 阿里支付转人工 提工单。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/ZcazGyW8DG.png!large)
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/UHQkxuK3CX.png!large)
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/wtnIAFuFwX.png!large)
- 工单记录给你们看看,证明一下,总结就是阿里客服公钥是对的,我本地生成就是错的。找了4个客服,对了4次。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/S2QFCAXs3P.png!large)
客服直接让我用它给我发的公钥。。。不要管证书解析,这是我就疑问,是不是我工具生成证书完全不对?!注意了,这是一个埋点!
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/Aqz57CFgy8.png!large)
开始思考,寻找解决办法
- 采用阿里官方sdk,发现还是不行 
- 采用python ,写一个秒级 更新订单状态 
py用的多的是下面这个包
github.com/fzlee/alipay/blob/maste...
阿里云官方pyhton 是这个包,但是我感觉写的太重了,肯定是pip的包好用。
github.com/fzlee/alipay/blob/maste...
python代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import time
import logging
import mysql.connector
from datetime import datetime
from alipay import AliPay
import json
# 配置日志
logging.basicConfig(
 level=logging.INFO,
 format='%(asctime)s [%(levelname)s] %(message)s',
 handlers=[
        logging.FileHandler("alipay_order_check.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)
# 数据库配置
DB_CONFIG = {
 'host': 'localhost',
 'user': 'test',
 'password': 'test',  # 替换为你的数据库密码
 'database': 'test',  # 替换为你的数据库名称
 'port': '3306',
 'pool_name': 'order_pool',
 'pool_size': 10,
 'use_pure': True,
}
# 支付宝配置
ALIPAY_CONFIG = {
 'app_id': '202100testtest890',  # 替换为你的应用ID
 'app_private_key_string': """-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtlryQ9iWi8UmTi9CJfTYzTvCA4urWTjf9CX+/esj+luP9P8R
n6iD2xJfBRdA7k4saDpNuELv7/pFkztIGkaBqag+5fQdrspK3A8+iOjB41ebRk2U
H3bpOKf
6VHYa+IQIeF+D/k4s2DJdi3H3nADNM6qp3XNCQIDAQABAoIBAQCRbojmORcfk3UQ
R7peoR5C19TMlRhryOM7SQ5LHbwMz/dIciBxD6lRDx6+5aPAKpJZ8Z3IRYIsBpJ0
cIP5iJ+iWe8H4B/IJcd8J6A8+jyffl/0uqxWR7SKnbjnevZTkRNxahvnjw6R9hyQ
4gBtdnSp0M6pQ0pdzfveC8pi7tr9U8WVtYIB7UpKV36+YfgjPpu8sYFl1a/8Iea1
5k4zyuKVQrmD4LutLjv8L/WXBeossnMSKsiY5E4HpyGvSVvTJD0RHFZ+5F0tGG1C
tLIZj+sLvx6gGlkrQq2pIMossKQBJeXro4v02BdiqDIiYPyiUXJGWeh/4FpefXJt
ZelEtvvBH8P6LGGjFHVXZ4Qk4oNg4hyxP
rMrRrynNLgL7Z9HTd20D+Sc97LugjMeeYzhCzru
zR9VWPm+OiAo1JuzbU7zwwghJuuyr05sShzJ2t9wdtBLv9c+oGZGR58=
-----END RSA PRIVATE KEY-----
""",
 # 'alipay_public_key_path': '../addons/epay/certs/alipayCertPublicKey_RSA2.crt',  # 替换为支付宝公钥路径
 'alipay_public_key_string': """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtlryQ9iWi8UmTi9CJfTY
aB9n7cyTGgpJYd1FZwZybK5sTCBIP2ezNJJSFu2S/0BLR+1DxT/UYxnoAD45v18N
G1AHtqakLmervaOtB17XfFX8oQPn6VHYa+IQIeF+D/k4s2DJdi3H3nADNM6qp3XN
CQIDAQAB
-----END PUBLIC KEY-----
""",  # 替换为支付宝公钥路径
 'sign_type': 'RSA2',
 'debug': False # 生产环境设为False
}
# 初始化支付宝客户端
def  init_alipay_client():
 try:
        logger.info("初始化支付宝客户端...")
 # 使用密钥字符串模式初始化
alipay_client = AliPay(
 appid=ALIPAY_CONFIG['app_id'],
 app_private_key_string=ALIPAY_CONFIG['app_private_key_string'],
 alipay_public_key_string=ALIPAY_CONFIG['alipay_public_key_string'],
 sign_type=ALIPAY_CONFIG['sign_type'],
 debug=ALIPAY_CONFIG['debug']
        )
        logger.info("支付宝客户端初始化成功")
 return alipay_client
 except  Exception  as e:
        logger.error(f"支付宝客户端初始化失败: {e}")
 import traceback
        logger.error(f"错误详情: {traceback.format_exc()}")
 raise
# 获取未支付的订单
def  get_unpaid_orders(db_conn):
 try:
cursor = db_conn.cursor(dictionary=True)
query =  """
            SELECT id, order_sn, transactionid, paytype, method, amount, createtime, expiretime
            FROM fa_shop_order
            WHERE paystate = 0 AND orderstate = 0 AND paytype = 'alipay' AND deletetime IS NULL
            AND goodsprice = 0.01
            AND year IS NOT NULL
            ORDER BY createtime DESC
            LIMIT 100
        """
        cursor.execute(query)
orders = cursor.fetchall()
        cursor.close()
 return orders
 except  Exception  as e:
        logger.error(f"获取未支付订单失败: {e}")
 raise
# 查询支付宝订单状态 - 修改后的版本,增加详细日志
def  query_alipay_order_status(order_sn, alipay_client):
 try:
        logger.info(f"准备查询订单状态: {order_sn}")
 # 准备查询参数
query_params = {'out_trade_no': order_sn}
        logger.info(f"查询参数: {query_params}")
 # 执行查询
result = alipay_client.api_alipay_trade_query(out_trade_no="order_sn")
 if result.get("trade_status", "") ==  "TRADE_SUCCESS":
paid =  True
 print("not paid...")
result = alipay_client.api_alipay_trade_query(**query_params)
        logger.info(f"查询结果: {result}")
 if result.get('code') ==  '10000':
 return {
 'success': True,
 'trade_status': result.get('trade_status'),
 'trade_no': result.get('trade_no'),
 'buyer_id': result.get('buyer_user_id'),
 'total_amount': result.get('total_amount')
            }
 else:
            logger.warning(f"查询返回非成功状态: {result}")
 return {
 'success': False,
 'error_code': result.get('code'),
 'error_msg': result.get('msg', '未知错误')
            }
 except  Exception  as e:
 import traceback
        logger.error(f"查询订单 {order_sn} 状态异常: {e}")
        logger.error(traceback.format_exc())
 return {
 'success': False,
 'error_msg': str(e)
        }
# 更新订单状态
def  update_order_status(db_conn, order_id, trade_no, pay_time):
 try:
cursor = db_conn.cursor()
query =  """
            UPDATE fa_shop_order
            SET paystate = 1,
transactionid = %s,
paytime = %s,
updatetime = %s
WHERE id = %s
        """
current_time =  int(time.time())
        cursor.execute(query, (trade_no, pay_time, current_time, order_id))
        db_conn.commit()
affected_rows = cursor.rowcount
        cursor.close()
 return affected_rows >  0
 except  Exception  as e:
        logger.error(f"更新订单 {order_id} 状态失败: {e}")
        db_conn.rollback()
 return  False
# 主函数
def  main():
    logger.info("开始执行订单支付状态检查脚本")
 try:
 # 创建数据库连接
 try:
            logger.info("尝试连接数据库...")
db_conn = mysql.connector.connect(**DB_CONFIG)
            logger.info("数据库连接成功")
 except mysql.connector.Error as err:
            logger.error(f"数据库连接失败: {err}")
 import traceback
            logger.error(f"错误详情: {traceback.format_exc()}")
 return
 # 初始化支付宝客户端
alipay_client = init_alipay_client()
 # 获取未支付订单
unpaid_orders = get_unpaid_orders(db_conn)
order_count =  len(unpaid_orders)
        logger.info(f"获取到 {order_count} 个未支付订单")
 # 如果没有订单需要处理,则结束脚本
 if order_count ==  0:
            logger.info("没有需要处理的订单,脚本结束")
            db_conn.close()
 return
orders_processed =  0
orders_updated =  0
 # 逐个处理订单
 for order in unpaid_orders:
orders_processed +=  1
order_sn = order['order_sn']
            logger.info(f"检查订单 {order_sn} ({orders_processed}/{order_count})")
 # 避免API调用过于频繁
            time.sleep(1)  # 增加到1秒,减少API调用频率
 # 查询支付宝订单状态
query_result = query_alipay_order_status(order_sn, alipay_client)
 if query_result['success']:
                logger.info(f"订单 {order_sn} 支付状态: {query_result['trade_status']}")
 # 判断交易是否成功
 if query_result['trade_status'] in ['TRADE_SUCCESS', 'TRADE_FINISHED']:
 # 更新订单状态为已支付
pay_time =  int(time.time())
updated = update_order_status(db_conn, order['id'], query_result['trade_no'], pay_time)
 if updated:
orders_updated +=  1
                        logger.info(f"订单 {order_sn} 状态已更新为已支付")
 else:
                        logger.warning(f"订单 {order_sn} 状态更新失败")
 else:
                logger.warning(f"查询订单 {order_sn} 失败: {query_result.get('error_msg', '未知错误')}")
        logger.info(f"脚本执行完毕,共处理 {orders_processed} 个订单,更新 {orders_updated} 个订单状态")
 except  Exception  as e:
        logger.error(f"脚本执行过程中发生错误: {e}")
 import traceback
        logger.error(f"错误详情: {traceback.format_exc()}")
 finally:
 # 关闭数据库连接
 if  'db_conn'  in  locals() and db_conn.is_connected():
            db_conn.close()
            logger.info("数据库连接已关闭")
    logger.info("脚本执行完成")
if  __name__  ==  "__main__":
    main()
这里py执行结果,也是一直报错。
于是我就想着,再看看pip包的说明吧。
结果我就发现了这么一句话。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/axhG5Nobg9.png!large)
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/SCOXVDG74A.png!large)
重大突破: 支付宝windows生成签名工具可能bug,用openssl好用点。
1.采用openssl,需要进入linux环境生成。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/Pqxz52X0um.png!large)
[root@wSsTBB1016841 ~]# mkdir opensslalipay
[root@wSsTBB1016841 ~]# cd opensslalipay/
[root@wSsTBB1016841 opensslalipay]# ls
[root@wSsTBB1016841 opensslalipay]# genrsa -out app_private_key.pem
-bash: genrsa: command not found
[root@wSsTBB1016841 opensslalipay]# openssl
OpenSSL> genrsa -out app_private_key.pem
Generating RSA private key, 2048 bit long modulus
........................................................+++
.........+++
e is 65537 (0x10001)
OpenSSL> pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem
OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem
writing RSA key
OpenSSL> exit
[root@wSsTBB1016841 opensslalipay]# ls
app_private_key.pem  app_private_key_pkcs8.pem  app_public_key.pem
得到这三个证书
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/RrLfjXXY5b.png!large)
但是easypay,要的是cert格式的。那就需要转换。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/wPMVpCCnju.png!large)
2. 证书转换pem转crt
基础概念
- PEM (Privacy Enhanced Mail): 这是一种基于Base64编码的文件格式,通常用于存储加密相关的文件,如私钥、公钥和证书。PEM文件以.pem为扩展名,内容通常以-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----包裹。
- CRT (Certificate): 这通常是PEM格式的一个别名,特别是在某些操作系统或软件中,CRT文件实际上是PEM格式的证书文件,只是扩展名不同。
转换方法
通常,PEM到CRT的转换并不需要改变文件内容,只是重命名文件扩展名即可。例如,如果你有一个名为certificate.pem的文件,你可以简单地将其重命名为certificate.crt
转换结果(手动复制改后缀)如下图![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/c01Zp0fPJw.png!large)
传上去。
3. 测试支付回调。成功了。。。
![[fastadmin] 第三十九篇 FastAdmin easypay 支付宝支付 回调 验签名错误 bug解决](https://cdn.learnku.com/uploads/images/202502/27/46135/aLnaLFXhVl.png!large)
总结:这种涉及到windows工具的,都不可靠。 证书生成还是得用linux。这一直是php好大好大的坑啊。
本作品采用《CC 协议》,转载必须注明作者和本文链接
 
           wangchunbo 的个人博客
 wangchunbo 的个人博客
         
           
           关于 LearnKu
                关于 LearnKu
               
                     
                     
                     粤公网安备 44030502004330号
 粤公网安备 44030502004330号