我孤身走在路上, 石子在雾中发亮,夜很安静,荒原面对太空,星星互诉衷肠
对接微信支付接口
对接微信支付接口

对接微信支付接口

项目是Pyhton+fastapi框架,在对接微信支付接口时真是一言难尽,腾讯的大佬们知道自己的接口文档很不好阅读吗?

1.回调函数没有说明请求方式,参数发送方式,只能自己来试咯,又不敢固定json或者URL-CODE,全部接收呗,最后试出来回调函数是POST,参数是json,下面是我项目的回调接口接收的参数:

{
'id': '2799da17-e092-539e-bf65-6eccc4c21a3d', 
'create_time': '2023-09-29T19:33:49+08:00', 
'resource_type': 'encrypt-resource', 
'event_type': 'TRANSACTION.SUCCESS', 
'summary': '支付成功', 
'resource': 
{
'original_type': 'transaction', 
'algorithm': 'AEAD_AES_256_GCM', 
'ciphertext': 'X5HRECMZnfX79+Md7mcb6+z/Hts3HmdluTOllo7rw/ga9NLQ2s2b/b6LeuZOsSPQgMKuAMUM88HT2mf2ZRzlVE44siKd8Dd4B8C5eI9DTUmqv7YlJC6m0TaRvwU3jN2xdBBhIErxb6kCdSvTuSohh8OY+d+T1wlJuRVbiZ519C+Rs6BnTKRcb2Ma/Rc1Axtz04hxK2VBLBHhlBXxeR7UhO0W51noP0eTYLGzPEPIbJrAFd+WbLM5cwec2/2stBpDUFuy5wAm3iSa7iPxy8b+y7JV7i2QeEhpm6a3+06YUxWzcrmr/fO5nbzHUOu2EOzMD/V7E14MWfdZpsAP7qKSWY6BeNKenQGO1+x4yLDV18z/7XVQOj0Wx5aDVIPr0cZ35eKkDPpbJhmuWxGC8t5JW6/SXClg+REWUmdNqyKWtLfjt3fXzTZAUjuwZMVKWtciy6SnuuSNeQC1Zxz8taGrLXsgfmSbjh1+BodnxtDbkShdaf5ysIDApkjdN8tUsSOYxE8lLj3fJ2xdSKLvWNPcaUhMxqYqxB43tnkKFdxFFXNMDwefK3lx3INEg==', 
'associated_data': 'transaction', 
'nonce': 'ef9nN1ofb93a'
}
}

部分敏感的内容我改了一下,大概就是这个意思,重要的信息放到ciphertext中,被加密了,你通过自己设置的秘钥解密就可以了,下面是代码示例

# 解码微信支付回调数据
def decode_wechat_pay_call_back(self, nonce, ciphertext, associated_data):
    # 获取微信支付API V3密钥
    key = get_conf.get_wxpay_apiv3_key
    # 将密钥转换为字节类型
    key_bytes = str.encode(key)
    # 将nonce转换为字节类型
    nonce_bytes = str.encode(nonce)
    ad_bytes = str.encode(associated_data)
    
    # 解码密文
    data = base64.b64decode(ciphertext)
    
    # 使用AES-GCM算法解密数据
    aesgcm = AESGCM(key_bytes)
    res = aesgcm.decrypt(nonce_bytes, data, ad_bytes)
    
    # 将解密后的数据转换为字符串
    str_data = res.decode("utf-8")
    
    # 将字符串数据转换为JSON对象
    return json.loads(str_data)

然后来说说支付部分:

1.按照文档要求生成随机字符串

random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))

2.完整的调用,其中如果缺少一些小的方法,自己实现一下就可以了,我是从配置文件读取的配置,你们要写死也无所谓

    # -*- coding: utf-8 -*-
"""
Author : Taering
Project : fastapi_openaiv2
Description :微信支付工具类
2023/9/28
"""
import hashlib
import hmac
import json
import random
import string
import time
from base64 import b64encode
from datetime import datetime, timedelta
from pathlib import Path
from urllib.parse import urlparse
import qrcode
import requests
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from util.config.getconfig import Conf
from util.global_logger_config import api_logger

BASE_DIR = Path(__file__).resolve().parent.parent

# 实例化读取配置文件
get_conf = Conf()

api_logger = api_logger()

class WeChatPay(object):
    """
    微信支付工具类
    """

    def __init__(self):
        # 从配置文件中获取微信支付的相关参数
        self.appid = get_conf.get_wxpay_appid  # APPID
        self.mchid = get_conf.get_wxpay_mchid  # 商户号
        self.payment_url = get_conf.get_wxpay_payment_url  # Native支付下单接口
        self.refund_url = get_conf.get_wxpay_refund_url  # 退款接口
        self.notify_url = get_conf.get_wxpay_notify_url  # 回调url
        self.serial_no = get_conf.get_wxpay_serial_no  # 商户证书序列号
        self.apiclient_key = str(BASE_DIR) + r'\util\keyfiles\wechatkeyfile\apiclient_key.pem'  # 本地证书路径

    # 生成签名
    def get_sign(self, sign_str):
        # 从本地读取私钥
        rsa_key = RSA.importKey(open(self.apiclient_key).read())
        # 使用PKCS1_v1_5进行签名
        signer = pkcs1_15.new(rsa_key)
        # 使用SHA256进行哈希
        digest = SHA256.new(sign_str.encode('utf8'))
        # 生成签名
        sign = b64encode(signer.sign(digest)).decode('utf-8')
        return sign

    def request(self, url: str, method: str, data: dict = None):
        # 将data转为json格式
        data = json.dumps(data) if data else ''
        # 生成随机字符串nonce_str
        random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
        # 获取当前时间戳
        timestamp = str(int(time.time()))
        # 拼接待签名字符串
        sign_str = '\n'.join([
            method.upper(),  # HTTP请求方法
            url.split(urlparse(url).netloc)[-1],  # path+args
            timestamp,  # 时间戳
            random_str,  # 请求随机串
            data, ''  # 请求报文主体
        ])  # 结尾空窜仅用于让后面多一个\n
        # 生成签名
        sign = self.get_sign(sign_str)

        # 设置请求头
        headers = {
            'Content-Type': 'application/json; charset=UTF-8',
            'Authorization': f'WECHATPAY2-SHA256-RSA2048 mchid="{self.mchid}",nonce_str="{random_str}",signature="{sign}",timestamp="{timestamp}",serial_no="{self.serial_no}"'
        }
        # 发起请求
        response = requests.request(url=url, method=method, data=data

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

+ 4 = 11