1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Python实现支付宝二维码支付(沙箱环境)

Python实现支付宝二维码支付(沙箱环境)

时间:2023-04-22 16:06:18

相关推荐

Python实现支付宝二维码支付(沙箱环境)

Python实现支付宝二维码支付

一.沙箱环境配置

1.登陆蚂蚁金融开放平台:

2.选择进入我的开放平台。寻找开发中心的研发服务。

3.点击沙箱环境—沙箱应用

4.这里博主已经配置好密钥了,所以在RSA2(SHA256)密钥(推荐)这边跟没有注册的不太一样。

如果没有配置过密钥请继续向下看,密钥配置完毕跳到代码处

5.下载RSA密钥生成工具:https://docs./291/105971

根据网页中的使用步骤配置即可

6.因为是沙箱测试,需要下载沙箱支付宝以便测试,但是沙箱支付宝仅支持安卓系统,需要一部安卓手机。

二.Python代码编写

1.首先准备需要的库:

如果是使用pycharm,博主在自己的github上已经配好了所需要的库,

可以直接访问博主的github:/PythonStriker/Alipay_for_QR_code

省下很多步骤如果不是使用paycharm,需要自己配置所需要的库:

2.代码如下所示:

pay.py

__author__ = 'PythonStriker'from self_Alipay import *import qrcode,timeAPPID = 自己的appid号private_key = '''-----BEGIN RSA PRIVATE KEY-----自己的支付宝私钥-----END RSA PRIVATE KEY-----'''public_key = '''-----BEGIN PUBLIC KEY-----自己的支付宝公钥-----END PUBLIC KEY-----'''class pay:def __init__(self,out_trade_no,total_amount,subject,timeout_express):self.out_trade_no = out_trade_noself.total_amount = total_amountself.subject = subjectself.timeout_express = timeout_expressdef get_qr_code(self,code_url):'''生成二维码:return None'''qr = qrcode.QRCode(version=1,error_correction=qrcode.constants.ERROR_CORRECT_H,box_size=10,border=1)qr.add_data(code_url) # 二维码所含信息img = qr.make_image() # 生成二维码图片img.save(r'自己需要保存的路径')print('二维码保存成功!')def query_order(self,out_trade_no: int):''':param out_trade_no: 商户订单号:return: Nonem'''_time = 0for i in range(600):time.sleep(1)result = alipay.init_alipay_cfg().api_alipay_trade_query(out_trade_no=out_trade_no)if result.get("trade_status", "") == "TRADE_SUCCESS":print('订单已支付!')print('订单查询返回值:', result)return True_time += 2return Falseif __name__ == '__main__':alipay = alipay(APPID, private_key, public_key)payer = pay(out_trade_no="订单号",total_amount= 价格,subject = "商品名字",timeout_express='订单超时取消时间 单位:s,m')dict = alipay.trade_pre_create(out_trade_no=payer.out_trade_no,total_amount=payer.total_amount,subject =payer.subject,timeout_express=payer.timeout_express )payer.get_qr_code(dict['qr_code'])payer.query_order(payer.out_trade_no)

代码有几处需要注意的地方:公钥私钥,appid,二维码图片保存地址,主函数中payer实例化订单号,价格,商品名字,超市取消时间都是需要自己填写的!

在主函数中,调用的方法已经写出来了,可以在别的模块中用相同的调用方法,博主会在之后的文章中演示,如何在别的模块中,完成调用,并验证是否付款成功。

self_Alipay.py

# -*- coding: UTF-8 -*-import base64import collectionsimport copyimport jsonfrom datetime import datetimefrom urllib import request, parseimport rsafrom alipay import AliPayAPP_ID = '需要填写'private_key = '''-----BEGIN RSA PRIVATE KEY-----需要填写-----END RSA PRIVATE KEY-----'''public_key = '''-----BEGIN PUBLIC KEY-----需要填写-----END PUBLIC KEY-----'''class alipay:def __init__(self, app_id, private_key, public_key, notify_url=None, charset='gbk', sign_type='RSA2',version='1.0', DEBUG=True):#需要注意,自己编码类型是否是RSA2self.requesturl = '/gateway.do' if DEBUG is False else "/gateway.do"self.private_key = private_keyself.public_key = public_keyself.params = dict(app_id=app_id, charset=charset, sign_type=sign_type, version=version,biz_content={}, timestamp='', notify_url=notify_url)def _sort(self, params):#print(collections.OrderedDict(sorted(dict(params).items(), key=lambda x: x[0])))return collections.OrderedDict(sorted(dict(params).items(), key=lambda x: x[0]))@staticmethoddef make_goods_etail(goods_detail=None, alipay_goods_id=None, goods_name=None, quantity=None, price=None,goods_category=None, body=None, show_url=None):params = dict(goods_detail=goods_detail, alipay_goods_id=alipay_goods_id, goods_name=goods_name,quantity=quantity, price=price, goods_category=goods_category, body=body, show_url=show_url)return dict(filter(lambda x: x[1] is not None, params.items()))def _make_sign(self, params, **kwargs):private_key = rsa.PrivateKey.load_pkcs1(kwargs.get('private_key', None) or self.private_key)sign = base64.b64encode(rsa.sign(params.encode(), private_key, "SHA-256")).decode('gbk')return signdef _check_sign(self, message, sign, **kwargs):message = self._sort(message)data = '{'for key, value in message.items():data += '"{}":"{}",'.format(key, value)data = data[:-1] + '}'sign = base64.b64decode(sign)public_key = rsa.PublicKey.load_pkcs1_openssl_pem(kwargs.get('public_key', None) or self.public_key)try:rsa.verify(data.encode(), sign, public_key)return Trueexcept Exception:return Falsedef _make_request(self, params, biz_content, **kwargs):buf = ''params['timestamp'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')params['biz_content'] = json.dumps(self._sort(biz_content))for key, value in kwargs.items():params[key] = valueparams = self._sort(params)for key in params:buf += '{}={}&'.format(key, params[key])params['sign'] = self._make_sign(buf[:-1], **kwargs)#print(params)# 发射http请求取回数据data = request.urlopen(self.requesturl, data=parse.urlencode(params).encode('gbk')).read().decode('gbk')#print(parse.urlencode(params).encode('gbk'))return datadef parse_response(self, params, **kwargs):sign = params['sign']if self._check_sign(dict(filter(lambda x: 'sign' not in x[0], params.items())), sign, **kwargs):return Trueelse:return Falsedef trade_pre_create(self, out_trade_no, total_amount, subject, seller_id=None, discountable_amount=None,undiscountable_amount=None, buyer_logon_id=None, body=None, goods_detail=None,operator_id=None, store_id=None, terminal_id=None, timeout_express=None, alipay_store_id=None,royalty_info=None, extend_params=None, **kwargs):""":param out_trade_no: 商户订单号,64个字符以内、只能包含字母、数字、下划线;需保证在商户端不重复.:param total_amount: 订单总金额,单位为元,精确到小数点后两位.:param subject: 订单标题.:param seller_id: 卖家支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID.:param discountable_amount:可打折金额. 参与优惠计算的金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]:param undiscountable_amount:不可打折金额. 不参与优惠计算的金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]:param buyer_logon_id:买家支付宝账号:param body:对交易或商品的描述:param goods_detail: 订单包含的商品列表信息.使用make_goods_etail生成. 其它说明详见:“商品明细说明”:param operator_id: 商户操作员编号:param store_id: 商户门店编号:param terminal_id: 商户机具终端编号:param timeout_express:该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天:param alipay_store_id:支付宝店铺的门店ID:param royalty_info: 描述分账信息 暂时无效:param extend_params: 业务扩展参数暂时无效:param kwargs: 公共参数可在此处暂时覆盖:return:"""params = copy.deepcopy(self.params)params['method'] = 'alipay.trade.precreate'total_amount = round(int(total_amount), 2)if discountable_amount:discountable_amount = round(int(discountable_amount), 2)if undiscountable_amount:undiscountable_amount = round(int(undiscountable_amount), 2)if discountable_amount:if undiscountable_amount is not None:if discountable_amount + undiscountable_amount != total_amount:return '传入打折金额错误'biz_content = dict(out_trade_no=out_trade_no[:64], total_amount=total_amount, seller_id=seller_id,subject=subject,discountable_amount=discountable_amount, undiscountable_amount=undiscountable_amount,buyer_logon_id=buyer_logon_id, body=body, goods_detail=goods_detail, operator_id=operator_id,store_id=store_id, terminal_id=terminal_id, timeout_express=timeout_express,alipay_store_id=alipay_store_id, royalty_info=royalty_info, extend_params=extend_params)#print(biz_content)resp = self._make_request(params, dict(filter(lambda x: x[1] is not None, biz_content.items())), **kwargs)#print(resp)check = eval(resp)resp = json.loads(resp)['alipay_trade_precreate_response']if self._check_sign(check['alipay_trade_precreate_response'], check['sign']):return respreturn Falsedef trade_refund(self, refund_amount, out_trade_no=None, trade_no=None,refund_reason=None, out_request_no=None, operator_id=None, store_id=None,terminal_id=None, **kwargs):""":param refund_amount: 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数:param out_trade_no: 商户订单号,不可与支付宝交易号同时为空:param trade_no: 支付宝交易号,和商户订单号不能同时为空:param refund_reason: 退款的原因说明:param out_request_no: 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。:param operator_id:商户的操作员编号:param store_id: 商户的门店编号:param terminal_id:商户的终端编号:param kwargs:公共参数可在此处临时覆盖:return:"""params = copy.deepcopy(self.params)params['method'] = 'alipay.trade.refund'refund_amount = round(float(refund_amount), 2)biz_content = dict(refund_amount=refund_amount, out_trade_no=out_trade_no, trade_no=trade_no,refund_reason=refund_reason, out_request_no=out_request_no, operator_id=operator_id,store_id=store_id, terminal_id=terminal_id)resp = self._make_request(params, dict(filter(lambda x: x[1] is not None, biz_content.items())), **kwargs)check = eval(resp)resp = json.loads(resp)['alipay_trade_refund_response']if self._check_sign(check['alipay_trade_refund_response'], check['sign']):return int(resp['code']) == 10000return Falsedef trade_query(self, out_trade_no, trade_no=None, **kwargs):params = copy.deepcopy(self.params)params['method'] = 'alipay.trade.query'biz_content = dict(out_trade_no=out_trade_no, trade_no=trade_no)resp = self._make_request(params, dict(filter(lambda x: x[1] is not None, biz_content.items())), **kwargs)check = eval(resp)resp = json.loads(resp)['alipay_trade_query_response']if self._check_sign(check['alipay_trade_query_response'], check['sign']) and resp['code'] == 10000:return respreturn Falsedef init_alipay_cfg(self):alipay = AliPay(appid=APP_ID,app_notify_url=None, # 默认回调urlapp_private_key_string=private_key,alipay_public_key_string=public_key, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,sign_type="RSA2", # RSA 或者 RSA2debug=True # 默认False ,若开启则使用沙盒环境的支付宝公钥)return alipay

该代码也有几处需要注意的地方:公钥密钥,appid,特别注意自己加密形式RSA 或者 RSA2之前博主吃过大亏。

#---------------------------------------------------------------------------------------------------------------------------#

特别注意事项:

1.这个支付宝端口支持的是非java端口,使用PKCS1加密方式密匙。

2.支付宝应用公钥,和支付宝公钥要分清楚。本代码中需要填写的是支付宝公钥!

3.其实PKCS8的小伙伴也不用悲伤,支付宝自带格式转换,如下图:

只需要将自己的PKCS8(JAVA适用)转换PKCS1(非JAVA适用)的密钥,本文代码依旧可以使用。

#---------------------------------------------------------------------------------------------------------------------------#

可以用自己的沙箱支付宝测试,是否可以支付。

附加成功示例:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。