2026-08-06 20:39:45 +08:00
|
|
|
import base64
|
|
|
|
|
import hashlib
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import re
|
|
|
|
|
import secrets
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from pathlib import Path
|
2026-08-21 23:48:29 +08:00
|
|
|
from typing import Literal
|
2026-08-06 20:39:45 +08:00
|
|
|
from zoneinfo import ZoneInfo
|
|
|
|
|
|
|
|
|
|
import django
|
|
|
|
|
import orjson
|
|
|
|
|
import pydash
|
|
|
|
|
import requests
|
2026-08-21 23:48:29 +08:00
|
|
|
import xmltodict
|
2026-08-06 20:39:45 +08:00
|
|
|
from Crypto.Cipher import AES
|
|
|
|
|
from Crypto.Hash import SHA256
|
|
|
|
|
from Crypto.PublicKey import RSA
|
|
|
|
|
from Crypto.PublicKey.RSA import RsaKey
|
|
|
|
|
from Crypto.Signature import pkcs1_15
|
|
|
|
|
from Crypto.Util.Padding import unpad
|
|
|
|
|
from dicttoxml import dicttoxml
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from pydantic import BaseModel, Field, SecretStr
|
|
|
|
|
from requests import Response
|
|
|
|
|
|
|
|
|
|
from sixGuoDjango.settings import base_dir_name
|
|
|
|
|
|
|
|
|
|
os.environ.setdefault(key="DJANGO_SETTINGS_MODULE", value=f"{base_dir_name}.settings")
|
|
|
|
|
django.setup()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class sixWechatPay六果泡泡支付(BaseModel):
|
2026-08-10 19:33:59 +08:00
|
|
|
mchid: str = Field(default="1700383419", alias="商户号", description="微信支付商户号")
|
|
|
|
|
appid: str = Field(default="wxf612e825377328f0", alias="商户号", description="微信支付商户号")
|
|
|
|
|
api_v3_key: str = Field(default="YWMGAIPTJTWZN4YB3YUTHWK34K9U9M1W", alias="APIv3密钥", description="用于回调解密")
|
|
|
|
|
api_v2_key: str = Field(default="OXRNKGGUYHGNJSSIHKFGVMAAOHRPXJAT", alias="APIv2密钥", description="仅老接口需要")
|
|
|
|
|
serial_no商户证书的序列号: str = Field(default="530160D54E8F56726F506DEE40D7FA49A558E8E0", description="商户证书的序列号")
|
2026-08-06 20:39:45 +08:00
|
|
|
# ---------- 小程序密钥 ----------
|
2026-08-10 19:33:59 +08:00
|
|
|
mini_program_app_secret: SecretStr = Field(default="8691f774e3c0c5a876b21a3e84109ef0", alias="小程序AppSecret")
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
# ---------- 商户API密钥对(用于签名请求) ----------
|
2026-08-10 19:33:59 +08:00
|
|
|
merchant_private_key_pem: str = Field(default=Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_key.pem").read_text(), alias="商户私钥PEM", description="apiclient_key.pem 内容")
|
2026-09-19 11:51:34 +08:00
|
|
|
merchant_public_key_pem: str = Field(default=Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/apiclient_cert.pem").read_text(), alias="商户公钥PEM", description="apiclient_cert.pem 内容(很少用到)")
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
# ---------- 微信支付公钥(用于验签和加密敏感字段) ----------
|
2026-08-10 19:33:59 +08:00
|
|
|
wechatpay_public_key_id: str = Field(default="PUB_KEY_ID_0117003834192026080500181856002000", alias="微信支付公钥ID")
|
|
|
|
|
wechatpay_public_key_pem: str = Field(default=Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/微信支付公钥.pem").read_text(), alias="微信支付公钥PEM", description="pub_key.pem 内容")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
# ---------- 平台证书(灰度过渡期备用) ----------
|
2026-08-21 23:48:29 +08:00
|
|
|
platform_cert_pem: str = Field(default=Path(settings.BASE_DIR).joinpath("wechat_微信支付证书/江苏六果科技有限公司支付证书/sixgou_ping_tai_zheng_shu_cert.pem").read_text(), alias="平台证书PEM",
|
|
|
|
|
description="wechatpay.pem 内容")
|
|
|
|
|
platform_cert_pem_id: str = Field(default="11D762828E947104028F2D045DE78FA806D0D4F2", description="平台证书的证收序列号ID")
|
|
|
|
|
pay_uri: str | None = Field(default=None, description="请求支付时需要的微信的url地址")
|
|
|
|
|
pay_请求体: dict = Field(default=None, description="发请求签名时需要的请求体")
|
2026-08-10 19:33:59 +08:00
|
|
|
pay_methon方法: Literal["GET", "POST", "PATCH"] = Field(default="POST", description="发请求签名时需要的请求体")
|
2026-08-21 23:48:29 +08:00
|
|
|
pay_Headers: dict = Field(default={}, description="生成的初始化请求头")
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
def model_post_init(self, __context):
|
2026-08-10 19:33:59 +08:00
|
|
|
pass
|
2026-08-21 23:48:29 +08:00
|
|
|
""""""
|
|
|
|
|
if self.pay_uri is None or self.pay_uri == "":
|
|
|
|
|
return None
|
|
|
|
|
url_data = re.search(r'/v3.*', string=self.pay_uri).group()
|
|
|
|
|
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
|
|
|
|
|
random_str = secrets.token_hex(nbytes=16) # 随机字符串
|
|
|
|
|
if isinstance(self.pay_请求体, str):
|
|
|
|
|
body_inner = self.pay_请求体
|
|
|
|
|
elif isinstance(self.pay_请求体, dict):
|
|
|
|
|
body_inner = json.dumps(self.pay_请求体)
|
|
|
|
|
elif self.pay_请求体 is None:
|
|
|
|
|
body_inner = ""
|
|
|
|
|
elif isinstance(self.pay_请求体, bytes):
|
|
|
|
|
body_inner = self.pay_请求体.decode()
|
|
|
|
|
else:
|
|
|
|
|
raise TypeError(f"不支持的请求体类型: {type(self.pay_请求体)}")
|
|
|
|
|
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{body_inner}\n"
|
|
|
|
|
# 构造一个哈希对象
|
|
|
|
|
hash_obj = SHA256.new(pay_signaturestring创建成功的签名串.encode(encoding="utf-8"))
|
|
|
|
|
# 加载商户私钥
|
|
|
|
|
# 调用了 RSA.import_key() 方法,它会从字符串或文件中导入一个 PEM 格式的 RSA 私钥,并返回一个 RsaKey 类型的对象
|
|
|
|
|
private_key: RsaKey = RSA.import_key(self.merchant_private_key_pem) # 用私钥来加密
|
|
|
|
|
# 生成签名 使用商户的 私钥进行签名
|
|
|
|
|
signature = pkcs1_15.new(rsa_key=private_key).sign(msg_hash=hash_obj)
|
|
|
|
|
# 对签名进行Base64编码,符合微信支付API要求
|
|
|
|
|
encoded_signature = base64.b64encode(s=signature).decode(encoding="utf-8")
|
|
|
|
|
# 组装成微信官方需要的数据;
|
|
|
|
|
data = {
|
|
|
|
|
"mchid": self.mchid,
|
|
|
|
|
"nonce_str": random_str,
|
|
|
|
|
"serial_no": self.serial_no商户证书的序列号,
|
|
|
|
|
"timestamp": utc_unix_timestamp,
|
|
|
|
|
"signature": encoded_signature,
|
|
|
|
|
} # 组装好的字典数据;
|
|
|
|
|
ftr = "WECHATPAY2-SHA256-RSA2048"
|
|
|
|
|
s_with_space = ftr.ljust(len(ftr) + 1) # 将字符串长度 +1(填充空格)
|
|
|
|
|
str_list = pydash.join(array=[f'{key}="{value}"' for key, value in data.items()], separator=",")
|
|
|
|
|
# 生成请求头
|
|
|
|
|
Authorization = f"{s_with_space}{str_list}"
|
|
|
|
|
headers = {"Content-Type": "application/json", "Authorization": Authorization, }
|
|
|
|
|
headers.update({"Wechatpay-Serial": self.wechatpay_public_key_id})
|
|
|
|
|
self.pay_Headers = headers
|
|
|
|
|
return None
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
def 验证签名串(self, response_headers, response_data: dict, ):
|
2026-08-21 23:48:29 +08:00
|
|
|
""" 注释 """
|
|
|
|
|
public_key = RSA.import_key(self.wechatpay_public_key_pem) # 在这里需要使用最新的微信支付公钥证书
|
2026-08-06 20:39:45 +08:00
|
|
|
Wechatpay_Timestamp = pydash.get(response_headers, "Wechatpay-Timestamp")
|
|
|
|
|
Wechatpay_Nonce = pydash.get(response_headers, "Wechatpay-Nonce")
|
|
|
|
|
Wechatpay_Signa = pydash.get(response_headers, "Wechatpay-Signature")
|
2026-08-21 23:48:29 +08:00
|
|
|
Wechatpay_Serial = pydash.get(response_headers, "Wechatpay-Serial")
|
2026-08-06 20:39:45 +08:00
|
|
|
response_data_str = orjson.dumps(response_data, ).decode(encoding="utf-8")
|
2026-08-21 23:48:29 +08:00
|
|
|
|
2026-08-06 20:39:45 +08:00
|
|
|
string_to_verify = f"{Wechatpay_Timestamp}\n{Wechatpay_Nonce}\n{response_data_str}\n" # 构造验签名串
|
|
|
|
|
hash_obj = SHA256.new(string_to_verify.encode())
|
2026-08-21 23:48:29 +08:00
|
|
|
if Wechatpay_Serial == self.platform_cert_pem_id:
|
|
|
|
|
public_key = RSA.import_key(self.platform_cert_pem)
|
|
|
|
|
# 6. 验证签名
|
|
|
|
|
if Wechatpay_Serial == self.wechatpay_public_key_id:
|
|
|
|
|
public_key = RSA.import_key(self.wechatpay_public_key_pem) # 在这里需要使用最新的微信支付公钥证书
|
2026-08-06 20:39:45 +08:00
|
|
|
try:
|
|
|
|
|
pkcs1_15.new(public_key).verify(msg_hash=hash_obj, signature=base64.b64decode(Wechatpay_Signa))
|
|
|
|
|
return True # 签名验证成功
|
|
|
|
|
except (ValueError, TypeError) as e:
|
2026-08-21 23:48:29 +08:00
|
|
|
print(e, "捕获了签名串验证不通过的错误") # 签名验证失败
|
|
|
|
|
raise "捕获了签名串验证不通过的错误"
|
2026-08-06 20:39:45 +08:00
|
|
|
|
2026-09-19 11:51:34 +08:00
|
|
|
def getHeaders构造签名串(self, ):
|
2026-08-21 23:48:29 +08:00
|
|
|
"""注释"""
|
2026-08-06 20:39:45 +08:00
|
|
|
url_data = re.search(r'/v3.*', string=self.pay_uri).group()
|
|
|
|
|
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
|
|
|
|
|
random_str = secrets.token_hex(nbytes=16) # 随机字符串
|
2026-08-21 23:48:29 +08:00
|
|
|
# 统一处理请求体,得到 body_inner 字符串
|
2026-08-06 20:39:45 +08:00
|
|
|
if isinstance(self.pay_请求体, str):
|
2026-08-21 23:48:29 +08:00
|
|
|
body_inner = self.pay_请求体
|
|
|
|
|
elif isinstance(self.pay_请求体, dict):
|
|
|
|
|
body_inner = json.dumps(self.pay_请求体)
|
|
|
|
|
elif self.pay_请求体 is None:
|
2026-08-06 20:39:45 +08:00
|
|
|
body_inner = ""
|
2026-08-21 23:48:29 +08:00
|
|
|
elif isinstance(self.pay_请求体, bytes):
|
2026-08-06 20:39:45 +08:00
|
|
|
body_inner = self.pay_请求体.decode()
|
2026-08-21 23:48:29 +08:00
|
|
|
else:
|
|
|
|
|
raise TypeError(f"不支持的请求体类型: {type(self.pay_请求体)}")
|
|
|
|
|
pay_signaturestring创建成功的签名串 = f"{self.pay_methon方法}\n{url_data}\n{utc_unix_timestamp}\n{random_str}\n{body_inner}\n"
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
# 构造一个哈希对象
|
|
|
|
|
hash_obj = SHA256.new(pay_signaturestring创建成功的签名串.encode(encoding="utf-8"))
|
|
|
|
|
# 加载商户私钥
|
|
|
|
|
# 调用了 RSA.import_key() 方法,它会从字符串或文件中导入一个 PEM 格式的 RSA 私钥,并返回一个 RsaKey 类型的对象
|
|
|
|
|
private_key: RsaKey = RSA.import_key(self.merchant_private_key_pem) # 用私钥来加密
|
|
|
|
|
# 生成签名 使用商户的 私钥进行签名
|
|
|
|
|
signature = pkcs1_15.new(rsa_key=private_key).sign(msg_hash=hash_obj)
|
|
|
|
|
# 对签名进行Base64编码,符合微信支付API要求
|
|
|
|
|
encoded_signature = base64.b64encode(s=signature).decode(encoding="utf-8")
|
|
|
|
|
# 组装成微信官方需要的数据;
|
|
|
|
|
data = {
|
|
|
|
|
"mchid": self.mchid,
|
|
|
|
|
"nonce_str": random_str,
|
|
|
|
|
"serial_no": self.serial_no商户证书的序列号,
|
|
|
|
|
"timestamp": utc_unix_timestamp,
|
|
|
|
|
"signature": encoded_signature,
|
|
|
|
|
} # 组装好的字典数据;
|
|
|
|
|
ftr = "WECHATPAY2-SHA256-RSA2048"
|
|
|
|
|
s_with_space = ftr.ljust(len(ftr) + 1) # 将字符串长度 +1(填充空格)
|
|
|
|
|
str_list = pydash.join(array=[f'{key}="{value}"' for key, value in data.items()], separator=",")
|
|
|
|
|
# 生成请求头
|
|
|
|
|
Authorization = f"{s_with_space}{str_list}"
|
|
|
|
|
headers = {"Content-Type": "application/json", "Authorization": Authorization, }
|
|
|
|
|
# headers.update({"Wechatpay-Serial": self.payment.微信支付公钥ID})
|
|
|
|
|
return headers
|
|
|
|
|
|
|
|
|
|
def 返回前端支付数据(self, prepay_id: str, wechat_appid: str):
|
|
|
|
|
"""
|
|
|
|
|
小程序调起支付
|
|
|
|
|
通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付。
|
|
|
|
|
@param prepay_ids
|
|
|
|
|
@type prepay_id:
|
|
|
|
|
@return:
|
|
|
|
|
@rtype:
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
utc_unix_timestamp = int(datetime.now(tz=ZoneInfo("utc")).timestamp())
|
|
|
|
|
random_string = secrets.token_hex(nbytes=30) # 随机字符串
|
|
|
|
|
# 组装微信官方要求的格式;
|
|
|
|
|
qian_mian_chuan = f"{wechat_appid}\n{utc_unix_timestamp}\n{random_string}\n{prepay_id}\n"
|
|
|
|
|
# # 使用组装好地签名串,进行sha256 哈希生成哈希对象
|
|
|
|
|
hash_obj = SHA256.new(qian_mian_chuan.encode())
|
|
|
|
|
# 生成商户私钥对象
|
|
|
|
|
# private_key = RSA.import_key( wechat_config.wechat私钥 )
|
|
|
|
|
private_key = RSA.import_key(self.merchant_private_key_pem)
|
|
|
|
|
# 生成签名
|
|
|
|
|
signature = pkcs1_15.new(private_key).sign(hash_obj)
|
|
|
|
|
# 将生成的签名串,转换为base格式
|
|
|
|
|
encoded_signature = base64.b64encode(signature).decode()
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
"appId": self.appid,
|
|
|
|
|
"timeStamp": str(utc_unix_timestamp),
|
|
|
|
|
"nonceStr": random_string,
|
|
|
|
|
"package": prepay_id,
|
|
|
|
|
"signType": "RSA",
|
|
|
|
|
"paySign": encoded_signature,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def getpay_jsapi发起支付(self, ):
|
|
|
|
|
# 发送请求
|
2026-08-21 23:48:29 +08:00
|
|
|
response: Response = requests.post(url=self.pay_uri, json=self.pay_请求体, headers=self.pay_Headers)
|
2026-08-06 20:39:45 +08:00
|
|
|
prepay_id = pydash.get(obj=response.json(), path="prepay_id", default=None)
|
|
|
|
|
# 验证请求后返回的数据是否为微信官方所发送;
|
|
|
|
|
验证签名结果 = self.验证签名串(response_data=response.json(), response_headers=response.headers)
|
|
|
|
|
if 验证签名结果:
|
|
|
|
|
prepay_id = f"prepay_id={prepay_id}"
|
|
|
|
|
# 调用方法生成返回给前端的对象
|
|
|
|
|
return self.返回前端支付数据(prepay_id=prepay_id, wechat_appid=self.appid, ) # 调用 返回前端支付数据()方法生成返回前端的支付字典
|
|
|
|
|
else:
|
|
|
|
|
raise "验证不通过"
|
|
|
|
|
|
|
|
|
|
def modegmc解密(self, nonce: str, ciphertext: str, associated_data: str, ) -> dict:
|
|
|
|
|
"""
|
|
|
|
|
支付成功或者退款回调时需要解密参数,微信返回的响应体.解密后可以获取支付成功或者退款的详细的数据;
|
|
|
|
|
@param nonce: // 加密使用的随机串初始化向量
|
|
|
|
|
@type nonce:
|
|
|
|
|
@param ciphertext: // Base64编码后的密文(需要解密)
|
|
|
|
|
@type ciphertext: (需要解密)
|
|
|
|
|
@param associated_data: // 附加数据包(可能为空)
|
|
|
|
|
@type associated_data:
|
|
|
|
|
@return:
|
|
|
|
|
@rtype:
|
|
|
|
|
"""
|
|
|
|
|
nonce_bytes = nonce.encode(encoding="utf-8")
|
|
|
|
|
ad_bytes = associated_data.encode(encoding="utf-8")
|
|
|
|
|
encrypted_data = base64.b64decode(ciphertext)
|
|
|
|
|
|
|
|
|
|
cipher = AES.new(key=self.api_v3_key.encode(), mode=AES.MODE_GCM, nonce=nonce_bytes)
|
|
|
|
|
# 处理附加关联数据(AAD) - 微信支付中通常是"transaction"
|
|
|
|
|
# 这部分数据在加密过程中被验证但未被加密
|
|
|
|
|
# 必须与加密时使用的附加数据完全一致
|
|
|
|
|
cipher.update(assoc_data=ad_bytes)
|
|
|
|
|
auth_tag = encrypted_data[-16:] # 提取认证标签(最后16 字节)
|
|
|
|
|
# 提取实际加密内容
|
|
|
|
|
ciphertext_bytes = encrypted_data[:-16] # 提取实际加密内容
|
|
|
|
|
decrypted_data = cipher.decrypt_and_verify(ciphertext=ciphertext_bytes, received_mac_tag=auth_tag)
|
|
|
|
|
# 回调解密数据: dict = json.loads(decrypted_data.decode())
|
|
|
|
|
回调解密数据: dict = orjson.loads(decrypted_data.decode(encoding="utf-8"))
|
|
|
|
|
return 回调解密数据
|
|
|
|
|
|
|
|
|
|
def callBack回调解密(self, headers, response_body: dict) -> dict:
|
|
|
|
|
"""
|
|
|
|
|
执行微信支付回调方法(获取返回的参数数据)
|
|
|
|
|
@param request:
|
|
|
|
|
@type request:
|
|
|
|
|
"""
|
|
|
|
|
self.验证签名串(response_headers=headers, response_data=response_body)
|
|
|
|
|
ciphertext = pydash.get(obj=response_body, path="resource.ciphertext", default=None)
|
|
|
|
|
associated_data = pydash.get(obj=response_body, path="resource.associated_data", default=None)
|
|
|
|
|
nonce = pydash.get(obj=response_body, path="resource.nonce", default=None)
|
|
|
|
|
wei_xin_zhi_fu_hui_diao_data = self.modegmc解密(
|
2026-09-19 11:51:34 +08:00
|
|
|
nonce=nonce, ciphertext=ciphertext, associated_data=associated_data,
|
2026-08-06 20:39:45 +08:00
|
|
|
)
|
|
|
|
|
return wei_xin_zhi_fu_hui_diao_data
|
|
|
|
|
|
|
|
|
|
def getpay_navite发起二维码支付(self, ):
|
|
|
|
|
""" 二维码支付,可以适用于 网站 的用户扫码支付 """
|
2026-09-19 11:51:34 +08:00
|
|
|
# headers = self.getHeaders构造签名串()
|
|
|
|
|
response = requests.post(url=self.pay_uri, headers=self.pay_Headers, json=self.pay_请求体)
|
2026-08-06 20:39:45 +08:00
|
|
|
生成的支付链接 = response.json()
|
|
|
|
|
return 生成的支付链接
|
|
|
|
|
|
2026-08-21 23:48:29 +08:00
|
|
|
def v2签名返回XML(self, sign_data):
|
2026-08-06 20:39:45 +08:00
|
|
|
"""v2版本的签名:将扫码支付的body转换为微信支付所要求的数据类型"""
|
2026-08-21 23:48:29 +08:00
|
|
|
sorted_dict = dict(pydash.sort_by(collection=sign_data.items(), iteratee=0))
|
2026-08-06 20:39:45 +08:00
|
|
|
# 拼接字符串: (将密钥添加到最末尾)
|
|
|
|
|
params_list_str = pydash.join(array=[f"{k}={v}" for k, v in sorted_dict.items()], separator="&") + "&key=" + self.api_v2_key
|
|
|
|
|
# 得到params_str就是需要 参与 签名的字符串
|
|
|
|
|
signature = hashlib.md5(string=params_list_str.encode()).hexdigest().upper() # 使用MD5加密模式
|
2026-08-21 23:48:29 +08:00
|
|
|
update后的数据 = pydash.set_(obj=sign_data, path="sign", value=signature)
|
2026-08-06 20:39:45 +08:00
|
|
|
xml = dicttoxml(obj=update后的数据, custom_root="xml", xml_declaration=False, attr_type=False, cdata=True)
|
2026-08-21 23:48:29 +08:00
|
|
|
return xml
|
|
|
|
|
|
|
|
|
|
def getpay_code扫用户付款码(self, body_data, ) -> dict:
|
|
|
|
|
""" """
|
|
|
|
|
xml = self.v2签名返回XML(sign_data=body_data)
|
|
|
|
|
fu_kuan_url = "https://api.mch.weixin.qq.com/pay/micropay"
|
|
|
|
|
res = requests.post(url=fu_kuan_url, data=xml)
|
|
|
|
|
# 返回的数据 是 ISO-8859-1 类型
|
|
|
|
|
responseStr = res.text.encode("ISO-8859-1")
|
|
|
|
|
# 将请求得到的数据 转换为字典格式;
|
|
|
|
|
xml_dict = xmltodict.parse(responseStr.decode())
|
|
|
|
|
# 得到请求结果并进行解密
|
|
|
|
|
print(xml_dict)
|
|
|
|
|
return xml_dict
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
def 解密群号(self, encryptedData, iv, sessionKey):
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
session_key_bytes = base64.b64decode(sessionKey)
|
|
|
|
|
encrypted_data_bytes = base64.b64decode(encryptedData)
|
|
|
|
|
iv_bytes = base64.b64decode(iv)
|
|
|
|
|
cipher = AES.new(key=session_key_bytes, mode=AES.MODE_CBC, iv=iv_bytes)
|
|
|
|
|
# 解密并去除填充
|
|
|
|
|
decrypted_data = unpad(cipher.decrypt(encrypted_data_bytes), AES.block_size).decode()
|
|
|
|
|
data_dict = orjson.loads(decrypted_data)
|
|
|
|
|
openGId = pydash.get(obj=data_dict, path="openGId")
|
|
|
|
|
timestamp = pydash.get(obj=data_dict, path="watermark.timestamp")
|
|
|
|
|
appid = pydash.get(obj=data_dict, path="watermark.appid")
|
|
|
|
|
return openGId, timestamp, appid
|
|
|
|
|
except Exception as e:
|
|
|
|
|
raise Exception(f"解密失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def 发起退款(self, ):
|
|
|
|
|
pass
|
|
|
|
|
uri = f"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
|
2026-09-19 11:51:34 +08:00
|
|
|
heardes = self.getHeaders构造签名串()
|
2026-08-06 20:39:45 +08:00
|
|
|
print(heardes)
|
|
|
|
|
response_data = requests.post(url=self.pay_uri, json=self.pay_请求体, headers=heardes)
|
|
|
|
|
print(response_data.json())
|
2026-09-19 11:51:34 +08:00
|
|
|
|
|
|
|
|
def getpay_发起提现(self):
|
|
|
|
|
pass
|
|
|
|
|
response: Response = requests.post(url=self.pay_uri, json=self.pay_请求体, headers=self.pay_Headers)
|
|
|
|
|
return response.json()
|
2026-08-06 20:39:45 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
pass
|