python 支付宝支付(1)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值