python 支付宝支付(1)
该方法是通过手动编写支付宝h5支付接口,但并并未实现,仅供参考,因为一直报签名错误,并且密钥相关的csr也都正确,经过多方询问和思考,后放弃,改用支付宝sdk,会在下一篇讲到。
如果可以给你提供一点思路,倍感荣幸!
如果能够提供解决思路,非常感谢!
(部分代码参考网上相关方法)
import collections, datetime, logging, base64, requests, OpenSSL, hashlib, re, rsa, os
from Crypto.Hash import SHA256, SHA1
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_PKCS1_v1_5
from Crypto.Signature import PKCS1_v1_5 as Signature_PKCS1_v1_5
from settings import const
from settings.dev import BASE_DIR
logging.basicConfig(
level=logging.ERROR,
format='%(asctime)s %(levelname)s %(message)s',
filemode='a', )
logger = logging.getLogger('')
def sn_string():
alipayRootCert = os.path.join(BASE_DIR, os.path.join('alipaycrt', "alipayRootCert.crt"))
root_file_li = open(alipayRootCert, 'r').read().split('\n\n')
# 支付宝根证书中有4套证书需要一一解析
alipay_root_cert_li = []
for root_str in root_file_li:
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, root_str)
certIssue = cert.get_issuer()
try:
if not re.match(b'sha.+WithRSAEncryption', cert.get_signature_algorithm()):
# 只有符合条件的是需要的,4套证书中只有两个有用(具体为啥咱也不太清楚)
continue
except:
continue
if certIssue.OU:
# 将机构名name和序列号serialNumber按照这样的顺序拼接
sn_string = 'CN=' + certIssue.CN + ',' + 'OU=' + certIssue.OU + ',' + 'O=' + certIssue.O + ',' + 'C=' + certIssue.C + str(cert.get_serial_number())
else:
sn_string = 'CN=' + certIssue.CN + ',' + 'O=' + certIssue.O + ',' + 'C=' + certIssue.C + str(
cert.get_serial_number())
alipay_root_cert_sn = hashlib.md5(sn_string.encode('utf-8')).hexdigest()
alipay_root_cert_li.append(alipay_root_cert_sn)
alipay_root_cert_sn = '_'.join(alipay_root_cert_li)
appCertPublicKey = os.path.join(BASE_DIR, os.path.join('alipaycrt', "appCertPublicKey_2016101500695766.crt"))
app_file_str = open(appCertPublicKey, 'r').read()
app_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, app_file_str)
certIssue = app_cert.get_issuer()
app_sn_string = 'CN=' + certIssue.CN + ',' + 'OU=' + certIssue.OU + ',' + 'O=' + certIssue.O + ',' + 'C=' + certIssue.C + str(app_cert.get_serial_number())
app_cert_sn = hashlib.md5(app_sn_string.encode('utf-8')).hexdigest()
return alipay_root_cert_sn, app_cert_sn
def load_alipay_public_key_string():
alipayCertPublicKey_RSA2 = os.path.join(BASE_DIR, os.path.join('alipaycrt', "alipayCertPublicKey_RSA2.crt"))
alipay_public_key_cert_string = open(alipayCertPublicKey_RSA2).read()
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, alipay_public_key_cert_string)
public_key = OpenSSL.crypto.dump_publickey(
OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey()
).decode("utf-8")
return public_key
def check_alipay(request):
alipay_req_dict = request.POST.dict() # 将传过来的支付宝参数转为普通字典
sign = alipay_req_dict.pop('sign') # 取出传过来的公钥
alipay_req_dict.pop('sign_type') # 去除传过来的sign_type
params = sorted(alipay_req_dict.items(), key=lambda e: e[0], reverse=False) # 取出字典元素按key的字母升序排序形成列表
message = "&".join(u"{}={}".format(k, v) for k, v in params).encode() # 将列表转为二进制参数字符串
public_key = load_alipay_public_key_string()
sign = base64.b64decode(sign)
status = bool(rsa.verify(message, sign, rsa.PublicKey.load_pkcs1_openssl_pem(public_key)))
class AliPay():
_GATEWAY = 'https://openapi.alipaydev.com/gateway.do?'
def __init__(self):
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.params = collections.OrderedDict()
self.params['app_id'] = const.ALIPAY[0]
self.params['method'] = 'alipay.trade.wap.pay'
self.params['charset'] = 'utf-8'
self.params['sign_type'] = 'RSA2'
self.params['timestamp'] = '{}'.format(timestamp)
self.params['version'] = '1.0'
def key_value_url(self, value):
"""
将将键值对转为 key1=value1&key2=value2
"""
params = sorted(value.items(), key=lambda e: e[0], reverse=False) # 取出字典元素按key的字母升序排序形成列表
message = "&".join(u"{}={}".format(k, v) for k, v in params)
return message
def rsa_encrypt(self, message, rsa_public_key):
"""use RSA to encrypt message,
:param message: 需要加密的内容
:param rsa_public_key: 公钥(字节类型)
:return: encrypt_msg_list密文列表
"""
pub_key = RSA.importKey("-----BEGIN RSA PRIVATE KEY-----" + '\n' +rsa_public_key + '\n'+"-----END RSA PRIVATE KEY-----")
# 加密对象
cipher = Cipher_PKCS1_v1_5.new(pub_key)
msg = str(message).encode('utf-8')
# 分段加密
default_encrypt_length = 245
length = default_encrypt_length
msg_list = [msg[i:i + length] for i in list(range(0, len(msg), length))]
# 加密后信息列表
encrypt_msg_list = []
for msg_str in msg_list:
cipher_text = base64.b64encode(cipher.encrypt(message=msg_str))
encrypt_msg_list.append(cipher_text)
return encrypt_msg_list[0]
def rsa2_encrypt(self, message, rsa_private_key):
"""use RSA2 to encrypt message,
:param message: 需要加密的内容
:param rsa_private_key: 公钥(字节类型)
:return: encrypt_msg_list密文列表
"""
# rsa_public_key = "-----BEGIN RSA PRIVATE KEY-----" + '\n' + rsa_public_key + '\n'+"-----END RSA PRIVATE KEY-----"
rsa_public_key = base64.b64decode(rsa_private_key)
pub_key = RSA.importKey(rsa_public_key)
# 加密后信息列表
msg = SHA256.new(message.encode())
# 加密对象
cipher = Signature_PKCS1_v1_5.new(pub_key)
signature = cipher.sign(msg)
cipher_text = base64.b64encode(signature)
cipher_text = cipher_text.decode()
# cipher_text = self.encodebytes(signature).decode("utf8").replace("\n", "")
return cipher_text
def pay(self, subject, out_trade_no, total_amount, quit_url):
"""
移动端h5支付
:param subject:订单标题
:param out_trade_no:商户订单号
:param total_amount:订单总金额。 单位为元,精确到小数点后两位
:param quit_url:用户付款中途退出返回商户网站的地址
:param product_code:产品码,默认值为QUICK_WAP_PAY
:return:
"""
self.params['biz_content'] = str({
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"quit_url": quit_url,
"product_code": 'QUICK_WAP_PAY'
})
string_sign = self.key_value_url(self.params)
sign = self.rsa2_encrypt(string_sign, const.ALIPAY[2])
print(sign)
self.params['sign'] = str(sign)
string_sign = self.key_value_url(self.params)
return self._GATEWAY + string_sign
def refund(self, out_trade_no, refund_amount):
"""
退款
:param out_trade_no: 商户订单编号
:param refund_amount: 退款金额,精确到0.01
:return:
"""
alipay_root_cert_sn, app_cert_sn = sn_string()
self.params['method'] = 'alipay.trade.refund'
self.params['alipay_root_cert_sn'] = alipay_root_cert_sn
self.params['app_cert_sn'] = app_cert_sn
# self.params['privateKey'] = const.ALIPAY[2]
self.params['biz_content'] = str({'out_trade_no': out_trade_no, 'refund_amount': refund_amount})
string_sign = self.key_value_url(self.params)
sign = self.rsa2_encrypt(string_sign, const.ALIPAY[2])
self.params['sign'] = sign
string_sign = self.key_value_url(self.params)
url = self._GATEWAY + string_sign
result_data = requests.post(url)
result_data = result_data.text
return result_data