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 相关文章推荐
Python pass 语句使用示例
Mar 11 Python
Python的装饰器用法学习笔记
Jun 24 Python
python安装cx_Oracle模块常见问题与解决方法
Feb 21 Python
网站渗透常用Python小脚本查询同ip网站
May 08 Python
python使用itchat库实现微信机器人(好友聊天、群聊天)
Jan 04 Python
python使用logging模块发送邮件代码示例
Jan 18 Python
使用Python如何测试InnoDB与MyISAM的读写性能
Sep 18 Python
python的等深分箱实例
Nov 22 Python
Python函数的默认参数设计示例详解
Dec 01 Python
Python实现鼠标自动在屏幕上随机移动功能
Mar 14 Python
PyQT5 实现快捷键复制表格数据的方法示例
Jun 19 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
Jan 05 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自动跳转中英文页面
2008/07/29 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(五)
2014/06/23 PHP
PHP使用GIFEncoder类生成的GIF动态图片验证码
2014/07/01 PHP
PHP基于方差和标准差计算学生成绩的稳定性示例
2017/07/04 PHP
Yii2.0实现生成二维码功能实例
2017/10/24 PHP
JavaScript 变量命名规则
2009/09/23 Javascript
基于JQuery的抓取博客园首页RSS的代码
2011/12/01 Javascript
jquery ajax 同步异步的执行 return值不能取得的解决方案
2012/01/08 Javascript
java必学必会之static关键字
2015/12/03 Javascript
jQuery实现简单的点赞效果
2020/05/29 Javascript
使用jquery.qrcode.min.js实现中文转化二维码
2016/03/11 Javascript
js中遍历对象的属性和值的方法
2016/07/27 Javascript
javascript基础知识之html5轮播图实例讲解(44)
2017/02/17 Javascript
JavaScript 中使用 Generator的方法
2017/12/29 Javascript
vue 动态改变静态图片以及请求网络图片的实现方法
2018/02/07 Javascript
vue.js的状态管理vuex中store的使用详解
2019/11/08 Javascript
vue实现移动端图片上传功能
2019/12/23 Javascript
解决Vue 给mapState中定义的属性赋值报错的问题
2020/06/22 Javascript
JavaScript this指向相关原理及实例解析
2020/07/10 Javascript
Python程序设计入门(4)模块和包
2014/06/16 Python
Python捕捉和模拟鼠标事件的方法
2015/06/03 Python
Python初学时购物车程序练习实例(推荐)
2017/08/08 Python
Python+PIL实现支付宝AR红包
2018/02/09 Python
11个Python Pandas小技巧让你的工作更高效(附代码实例)
2019/04/30 Python
python实现基于朴素贝叶斯的垃圾分类算法
2019/07/09 Python
keras 特征图可视化实例(中间层)
2020/01/24 Python
阿迪达斯墨西哥官方网站:adidas墨西哥
2017/11/03 全球购物
台湾最大银发乐活百货:乐龄网
2018/05/21 全球购物
九年级体育教学反思
2014/01/23 职场文书
党员一句话承诺大全
2014/03/28 职场文书
学生夜不归宿检讨书
2014/09/23 职场文书
财务务虚会发言材料
2014/10/20 职场文书
2015年基层党组织公开承诺书
2015/01/21 职场文书
乡镇科协工作总结2015
2015/05/19 职场文书
公司联欢会主持词
2015/07/04 职场文书
Ubuntu安装Mysql+启用远程连接的完整过程
2022/06/21 Servers