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


Posted in Python onMay 07, 2019

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

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

一、支付宝支付

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

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

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

import OpenSSL
import json
import time
import urllib
import 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 time
import hashlib
import urllib, urllib2
import base64
import OpenSSL
from 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 format
UNIONPAY_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 相关文章推荐
Pyhton中单行和多行注释的使用方法及规范
Oct 11 Python
解决pycharm工程启动卡住没反应的问题
Jan 19 Python
python利用多种方式来统计词频(单词个数)
May 27 Python
详解利用OpenCV提取图像中的矩形区域(PPT屏幕等)
Jul 01 Python
用Pytorch训练CNN(数据集MNIST,使用GPU的方法)
Aug 19 Python
python+jinja2实现接口数据批量生成工具
Aug 28 Python
Python爬虫实现的根据分类爬取豆瓣电影信息功能示例
Sep 15 Python
浅谈PyTorch的可重复性问题(如何使实验结果可复现)
Feb 20 Python
基于tensorflow for循环 while循环案例
Jun 30 Python
python调用有道智云API实现文件批量翻译
Oct 10 Python
最新PyCharm从安装到PyCharm永久激活再到PyCharm官方中文汉化详细教程
Nov 17 Python
Python中requests做接口测试的方法
May 30 Python
详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
May 07 #Python
Scrapy-Redis结合POST请求获取数据的方法示例
May 07 #Python
Python数据类型之Set集合实例详解
May 07 #Python
Python数据类型之Dict字典实例详解
May 07 #Python
Python分支语句与循环语句应用实例分析
May 07 #Python
Python正则表达式实现简易计算器功能示例
May 07 #Python
深入浅析Python 中 is 语法带来的误解
May 07 #Python
You might like
php环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
2006/11/17 PHP
一个简单的PHP投票程序源码
2007/03/11 PHP
PHP file_get_contents函数读取远程数据超时的解决方法
2015/05/13 PHP
php下的原生ajax请求用法实例分析
2020/02/28 PHP
JavaScript中出现乱码的处理心得
2009/12/24 Javascript
jquery之别踩白块游戏的简单实现
2016/07/25 Javascript
JavaScript实现移动端轮播效果
2017/06/06 Javascript
ES6中数组array新增方法实例总结
2017/11/07 Javascript
利用Angular2的Observables实现交互控制的方法
2018/12/27 Javascript
[02:07]DOTA2新英雄展现中国元素,完美“圣典”亮相央视
2016/12/19 DOTA
跟老齐学Python之传说中的函数编写条规
2014/10/11 Python
在Python中使用CasperJS获取JS渲染生成的HTML内容的教程
2015/04/09 Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
2017/07/24 Python
python线程中同步锁详解
2018/04/27 Python
Python机器学习k-近邻算法(K Nearest Neighbor)实例详解
2018/06/25 Python
python保存二维数组到txt文件中的方法
2018/11/15 Python
python版飞机大战代码分享
2018/11/20 Python
Python寻找两个有序数组的中位数实例详解
2018/12/05 Python
解决Pandas的DataFrame输出截断和省略的问题
2019/02/08 Python
Pandas_cum累积计算和rolling滚动计算的用法详解
2019/07/04 Python
python requests使用socks5的例子
2019/07/25 Python
HTML5新控件之日期和时间选择输入的实现代码
2018/09/13 HTML / CSS
介绍一下EJB的分类及其各自的功能及应用
2016/08/23 面试题
物业管理毕业生的自我评价
2014/02/17 职场文书
课程改革实施方案
2014/03/16 职场文书
期末评语大全
2014/05/04 职场文书
科学发展观活动总结
2014/08/28 职场文书
优秀班主任事迹材料
2014/12/16 职场文书
单位委托函范文
2015/01/29 职场文书
答谢酒会主持词
2015/07/02 职场文书
七年级生物教学反思
2016/02/20 职场文书
python Polars库的使用简介
2021/04/21 Python
JVM上高性能数据格式库包Apache Arrow入门和架构详解(Gkatziouras)
2021/05/26 Servers
详解SpringBoot异常处理流程及原理
2021/06/21 Java/Android
Python实现DBSCAN聚类算法并样例测试
2021/06/22 Python
解决IDEA翻译插件Translation报错更新TTK失败不能使用
2022/04/24 Python