ECN>> Pay>> 返回
项目作者: iakisey

项目描述 :
alipay & wechat sdk base on python3
高级语言: Python
项目地址: git://github.com/iakisey/Pay.git
创建时间: 2016-12-30T04:47:58Z
项目社区:https://github.com/iakisey/Pay

开源协议:

下载


场景介绍

  • 前端:

    • 基于apicloud开发平台的H5
  • 后端:

    • 基于tornado的python后端框架

开发资料:alipay

缘由:支付宝没有提供基于Python的SDK,也没有提供类似的接口调试工具,开发过程中踩过好几个坑,特别是在==SHA1withRSA==签名与验签部分。

具体过程

准备

生成一对公钥、密钥

公钥保存在支付宝应用公钥中

私钥保存在服务器中

请求参数

文档:App支付请求参数说明

代码:

  1. def gen_parameters(self, out_trade_no, total_amount, subject):
  2. self.__parameters = {
  3. 'app_id': self.__appid,
  4. 'method': 'alipay.trade.app.pay',
  5. 'charset': 'utf-8',
  6. 'sign_type': 'RSA',
  7. 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  8. 'version': '1.0',
  9. 'notify_url': self.__notify_url,
  10. 'biz_content': json.dumps(
  11. {
  12. 'subject': subject, # 主题
  13. 'out_trade_no': out_trade_no, # 订单编号
  14. 'total_amount': total_amount, # 总金额
  15. 'product_code': 'QUICK_MSECURITY_PAY'},
  16. sort_keys=True).replace(' ', '')
  17. }

其中biz_content字段需要注意:这个是具体业务参数的集合,类型是字符串,各个具体参数需要按字母排序,还要去除掉空字符。

未签名原始字符串

请求参数按照key=value&key=value方式拼接的未签名原始字符串

  1. unsigned_str = '&'.join('{}={}'.format(k, v) for k, v in sorted(self.__parameters.items()))

需要注意的是:排序前要对参数字典进行按字母顺序排序

签名

支付宝采取SHA1withRSA签名方式,而python标准库没有提供相应的库来支持,所以这里采用第三方库pycrypto

安装:pip install pycrypto

引用:

  1. from Crypto.Hash import SHA
  2. from Crypto.PublicKey import RSA
  3. from Crypto.Signature import PKCS1_v1_5

注:这里还需要一对rsa的公、密钥,公钥需要上传到支付宝的应用公钥,私钥保存在服务器上,待会要引用私钥地址。

具体实现:

  1. from base64 import b64encode
  2. def __ali_sign(self, unsigned_str):
  3. with open(self.__private_key, 'r') as f:
  4. private_key = RSA.importKey(f.read())
  5. signer = PKCS1_v1_5.new(private_key)
  6. digest = SHA.new()
  7. digest.update(unsigned_str.encode())
  8. sign = signer.sign(digest)
  9. return b64encode(sign).decode()

获得最终的请求字符串

支付宝给出的方式:

最后对请求字符串的所有一级value(biz_content作为一个value)进行encode,编码格式按请求串中的charset为准,没传charset按UTF-8处理,获得最终的请求字符串

我的建议的:
先对构建的参数字典的每个value指进行quote,最后再拼接sign字段

  1. from urllib.parse import quote_plus
  2. self.__parameters = {k: quote_plus(v) for k, v in self.__parameters.items()}
  3. signed_str = '{}={}'.format(k, v) for k, v in sorted(self.__parameters.items()))
  4. signed_str += '&sign=' += quote_plus(sign)

最后讲signed_str传给前端

代码地址