侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

python实现银联支付和支付宝支付接入

Python  /  管理员 发布于 7年前   172

本文实例为大家分享了python银联支付和支付宝支付接入的具体代码,供大家参考,具体内容如下

前置条件:需要安装Python的OpenSSL模块,我使用的版本是16.1.0,可以使用pip install pyopenssl来安装

一、支付宝支付

1. 使用RSA公钥加密系统进行签名和签名验证,需要自己生成一个RSA私钥和对应的一个RSA公钥(在Linux下可以使用ssh-keygen命令来生成),公钥需要上传至支付宝,供支付宝对开发者发送的请求做签名验证使用;而同时支付宝会提供一个RSA公钥给开发者,开发者使用这个公钥来验证支付宝的回调请求的合法性。

2. 整个接入过程最核心的工作就是构建一个合法的请求报文,这个可以参考支付宝的相关文档;其次是对请求报文的内容进行RSA签名,并将签名随请求报文一并发送。

核心的签名和报文构建代码如下:

import OpenSSLimport jsonimport timeimport urllibimport base64 from django.conf import settings def build_sign(param_map, sign_type="RSA"): ''' Doc: https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105351&docType=1 ''' # 将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。 sort_param = sorted([(key, unicode(value, settings.ALIPAY_CHARSET).encode(settings.ALIPAY_CHARSET)) for key, value in param_map.iteritems()], key=lambda x: x[0]) # 将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为待签名字符串。SDK中已封装签名方法,开发者可直接调用,详见SDK说明。 # 如自己开发,则需将待签名字符串和私钥放入SHA1 RSA算法中得出签名(sign)的值。 content = '&'.join(['='.join(x) for x in sort_param]) return base64.encodestring(OpenSSL.crypto.sign(settings.ALIPAY_APP_PRIVATE_KEY_OBJ, content, 'sha1')) def build_params(out_trade_no, subject, body, total_amount): ''' Doc:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.MVkRGo&treeId=193&articleId=105465&docType=1 将参数按照支付宝规定组织并签名之后,返回 ''' params = {} # 获取配置文件 params['app_id']   = settings.ALIPAY_APPID params['method']   = settings.ALIPAY_METHOD params['format']   = settings.ALIPAY_FORMAT params['charset']   = settings.ALIPAY_CHARSET params['sign_type']   = settings.ALIPAY_SIGN_TYPE params['sign_type']   = settings.ALIPAY_SIGN_TYPE params['timestamp']   = time.strftime('%Y-%m-%d %H:%M:%S') params['version']   = settings.ALIPAY_VERSION params['notify_url']  = settings.ALIPAY_NOTIFY_URL  # 业务参数 params['biz_content'] = {} params['biz_content']['body']    = body   # 订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里 params['biz_content']['subject']   = subject  # 商品的标题/交易标题/订单标题/订单关键字等。 params['biz_content']['out_trade_no']  = out_trade_no # 商户网站唯一订单号  params['biz_content']['total_amount']  = '%.2f' % (float(total_amount) / 100) # 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]  params['biz_content']['product_code']  = settings.ALIPAY_APP_PRODUCT_CODE params['biz_content']      = json.dumps(params['biz_content'], separators=(',', ':'))  params['sign'] = build_sign(params)  return urllib.urlencode(params) def check_sign(message, sign): '''Doc: https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.dDRpeK&treeId=204&articleId=105301&docType=1''' try:  OpenSSL.crypto.verify(settings.ALIPAY_PUBLIC_KEY_OBJ, sign, message, 'SHA1')  return True except Exception as _:  return False

在读取支付宝公钥的时候,由于OpenSSL模块使用的是X509格式的证书,所以需要做以下的处理(用于对发起支付报文进行签名):

# 支付宝开发者公钥(支付宝生成)ALIPAY_PUBLIC_KEY = os.path.join(BASE_DIR, 'utils/paycenter/alipay/certs/alipay_public_key')_ALIPAY_PUBLIC_KEY_OBJ_PUB = OpenSSL.crypto.load_publickey(OpenSSL.crypto.FILETYPE_PEM, open(ALIPAY_PUBLIC_KEY).read())_ALIPAY_PUBLIC_KEY_OBJ_X509 = OpenSSL.crypto.X509()_ALIPAY_PUBLIC_KEY_OBJ_X509.set_pubkey(_ALIPAY_PUBLIC_KEY_OBJ_PUB)ALIPAY_PUBLIC_KEY_OBJ = _ALIPAY_PUBLIC_KEY_OBJ_X509

载入开发者生成的私钥的代码为(用于验证支付宝回调请求的合法性):

# 支付宝开发者应用私钥(接入方生成)ALIPAY_APP_PRIVATE_KEY = os.path.join(BASE_DIR, 'utils/paycenter/alipay/certs/alipay_app_private_key')ALIPAY_APP_PRIVATE_KEY_OBJ = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, open(ALIPAY_APP_PRIVATE_KEY).read(), None)

二、银联支付

1. 银联支付(网关支付)与支付宝支付基本上遵循了同样的流程,但是在发起支付的请求报文和签名、验证签名等方面存在细微的差别,特别是在签名和验证签名时,支付宝是直接对报文内容进行了RSA加密,但是银联却是首先对签名内容取SHA1的摘要,继而对此摘要做RSA加密,这点在build_sign函数中就可以很明显地看出来。

2. 银联支付的证书文件申请流程比较繁琐,并且其格式也和支付宝使用的不同,我们申请到的私钥证书文件是以PKCS12的格式保存的,并且需要注意在从指定位置下载此证书后,导出证书时一定要将密码设置为6位的整数数字,之后,还需要将PKCS12格式的证书文件上传至指定位置并启用才可以正常使用此证书。

核心的签名和报文构建代码如下:

import timeimport hashlibimport urllib, urllib2import base64import OpenSSLfrom django.conf import settings def build_sign(param_map, sign_type="RSA"): '''构建签名''' # 将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。 sort_param = sorted([(key, unicode(value, settings.UNIONPAY_ENCODING).encode(settings.UNIONPAY_ENCODING)) for key, value in param_map.iteritems()], key=lambda x: x[0]) content = '&'.join(['='.join(x) for x in sort_param]) message = hashlib.sha1(content).hexdigest() return base64.b64encode(OpenSSL.crypto.sign(settings.UNIONPAY_PRIVATE_KEY_OBJ, message, 'sha1')) def build_params(out_trade_no, total_amount): params = {} # 获取配置信息 params['accType'] = settings.UNIONPAY_ACC_TYPE params['accessType'] = settings.UNIONPAY_ACCESS_TYPE params['backUrl'] = settings.UNIONPAY_BACK_URL params['frontUrl'] = settings.UNIONPAY_FRONT_URL params['bizType'] = settings.UNIONPAY_BIZ_TYPE params['certId'] = settings.UNIONPAY_CERT_ID params['channelType'] = settings.UNIONPAY_CHANNEL_TYPE params['currencyCode'] = settings.UNIONPAY_CURRENCY_CODE params['encoding'] = settings.UNIONPAY_ENCODING params['merId'] = settings.UNIONPAY_MER_ID params['signMethod'] = settings.UNIONPAY_SIGN_METHOD params['txnType'] = settings.UNIONPAY_TXN_TYPE params['txnSubType'] = settings.UNIONPAY_TXN_SUBTYPE params['version'] = settings.UNIONPAY_VERSION  params['orderId'] = out_trade_no params['txnAmt'] = '%d' % int(total_amount) # 单位为分 params['txnTime'] = time.strftime('%Y%m%d%H%M%S') #   params['signature'] = build_sign(params)#  return params return urllib.urlencode(params) def check_sign(message, sign): try:  OpenSSL.crypto.verify(settings.UNIONPAY_PUBLIC_KEY_OBJ, sign, message, 'SHA1')  return True except Exception as _:  return False

商户私钥证书的载入方法(用户对发起支付的报文进行签名):

# 商户私钥证书UNIONPAY_APP_PRIVATE_KEY_CERT = os.path.join(UNIONPAY_CERTS_PATH, UNIONPAY_APP_PRIVATE_KEY_CERT_FILENAME) # PKCS12 formatUNIONPAY_PRIVATE_KEYSTORE = OpenSSL.crypto.load_pkcs12(open(UNIONPAY_APP_PRIVATE_KEY_CERT).read(), UNIONPAY_APP_PRIVATE_KEY_CERT_PASSWORD)UNIONPAY_PRIVATE_KEY_OBJ = UNIONPAY_PRIVATE_KEYSTORE.get_privatekey()

银联公钥证书的载入方法(用于验证银联回调的合法性):

# 银联公钥证书UNIONPAY_PUBLIC_KEY_CERT = os.path.join(UNIONPAY_CERTS_PATH, UNIONPAY_PUBLIC_KEY_CERT_FILENAME)UNIONPAY_PUBLIC_KEY_OBJ = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open(UNIONPAY_PUBLIC_KEY_CERT).read())

后记:银联支付接入过程中,参考过其官方提供的一个Python实现的接口,里面同时使用了python的rsa模块和OpenSSL模块,并且对证书的格式做了各种处理,但是这些似乎是没有什么必要,只使用OpenSSL模块就完全可以完成相关的工作。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    python使用threading.Condition交替打印两个字符
    下一条:
    详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客