支付宝开发详细流程【沙箱环境】

1,128 阅读5分钟

「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战

支付宝开发详细流程

1. 正式环境(需要营业执照等信息)

2. 沙箱环境(模拟真实的环境)

2.1 申请开通沙箱环境

2.2 生成密钥

  • 密钥用于以后对URL中添加的参数进行加密和校验 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YO5iTGmB-1596507916908)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803144430623.png)]

2.2.1 下载密钥生成器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lyagKyfC-1596507916910)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803144329714.png)]

2.2.2 生成密钥

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FfjJsu26-1596507916911)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803144950121.png)]

  • 会生成一对密钥,同时生成两个 txt文件
    • 应用公钥
    • 应用私钥

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hNTQYsG7-1596507916913)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803145116924.png)]

  • 我们将两个文件放到项目中,方便以后使用 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4R6DkFVE-1596507916914)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803145759859.png)]

2.2.3 上传应用公钥并获得支付宝公钥

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndJXW5Jo-1596507916915)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803145605267.png)]

  • 点击 保存设置 后就会生成支付宝公钥 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3iTt8vD-1596507916917)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803145650359.png)]

  • 然后把支付宝公钥也放在项目中,方便以后使用 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mD8munt5-1596507916919)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803145828421.png)]

  • 至此,我们共获取到三个密钥:

    • 应用公钥
      • 生成支付宝公钥后就没用处了
    • 应用私钥
      • 对以后URL中传入的数据进行签名加密用
    • 支付宝公钥(通过应用公钥生成)
      • 在页面支付成功后跳转回来时,对支付宝给我们传的值进行校验

3. 账户信息和测试APP

  • 下载沙箱版支付宝app【仅提供Android版本】 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U1qYPvmo-1596507916921)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803150312543.png)]

  • 然后查看沙箱账号登录

    • 买家信息
    • 卖家信息

注意: 不要使用自己的支付宝账号登录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTaNiVcu-1596507916921)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803151058221.png)]

4. SDK & API

一般都会有两个支持

  • SDK,现成的Python模块【优先使用】

    1. 安装模块
    2. 基于模块实现想要的功能
    
  • API,提供一个URL

    1. 自己手动对URL进行处理和加密
    

4.1 SDK

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nyruWYLB-1596507916922)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803151513182.png)]

  • 接入文档中都是通过工具实现的,而我们需要通过代码进行实现,点击下载开发工具包 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PUbSLdP0-1596507916923)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803151821254.png)]

4.2 API

  • 支付API [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i6Zz6iCY-1596507916924)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803152603186.png)]

  • 要使用支付功能,所以这里选择统一收单下单并支付页面接口 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBjWnRl9-1596507916926)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803152919532.png)]

参数构造

# 跳转到这个地址: 【网关?参数】组成
网关 = https://openapi.alipaydev.com/gateway.do
params = {
   	'app_id': 'xxxx',
    'method': 'alipay.trade.page.pay',
    'format': 'JSON',
    'return_url': '支付成之后跳转到的页面地址(GET请求)',
    'notify_url': '跳转到return_url的同时向这个地址发送POST请求',
    'charset': 'utf-8',
    'sign_type': 'RSA2',
    'sign': '签名',
    'timestamp': 'yyyy-MM-dd HH:mm:ss',
    'version': '1.0',
    'biz_content': {
        'out_trade_no': '订单号',
        'product_code': 'FAST_INSTANT_TRADE_PAY',
        'total_amount': 88.88,
        'subject': '订单标题'
    }
}

如果支付成功之后,服务器宕机,如何处理? 向notify_url发请求,支付成功,请求更新状态, 服务器宕机,支付宝访问不到,则会在24小时以内:支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h); 接收到支付宝请求之后,返回的数据不正确,同上。 返回一个 success   支付结果异步通知

5. 支付宝签名

5.1 签名原理

1. 将参数中 空、文件、字节、sign 剔除
	params.pop(sign)

2. 排序,对参数中所有的key进行从小大到大排序 sort(params)
	按照第一个字符的键值 ASCII 码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值 ASCII 码递增排序

3. 将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用 & 字符连接起来,此时生成的字符串为待签名字符串。
	待签名字符串 = "app_id=xxxx&method=alipay.trade.page.pay&...."
	注意: 1. 有字典应该转换为字符串
		  2. 字符串中间不能有空格(真操蛋的要求,json.dumps(xxx)后默认就会有空格
		     可以使用 json.dumps(xxx, separators=(',',':')))
		  
4. 使用各自语言对应的 SHA256WithRSA 签名函数并利用商户(应用)私钥对待签名字符串进行签名,并进行 Base64 编码
	- result= 使用SHA256WithRSA函数和私钥对待签名字符串进行签名
	- 签名 = 对result进行Base64编码
	
	把签名再添加回params字典中 params[sign] = 签名
	注意: base64编码之后,内部不能有换行符
		签名.replace('\n', '')
	
5. 再将所有的参数拼接起来

	注意: 在拼接URL时不能出现 ;,( 等字符,提前将特殊字符转换为URL转义的字符(URL编码)
	`from urllib.parse import quote_plus`

5.2 签名实现

# pip install pycrypto
# windows 安装可能会报错【如下图】
# 可以下载安装 pycryptodome 这个库
# pycryptodome.xxx.whl 安装方法:
#	进入安装目录 pip install pycryptodome.xxx.whl

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xHvAa1d9-1596507916927)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200803171241856.png)]

下载也有点麻烦,我这里把下载好的几个文件放在网盘,需要自行下载即可,我这里放的版本有 【py27、py35、py36】,其他版本可自行下载

注意:根据自己的python版本安装,例如: 文件名中的py35代表python3.5

链接:pan.baidu.com/s/1z1kT-Qjd… 提取码:kjnd

# 构造字典
params = {
    'app_id': "2021000117635347",
    'method': 'alipay.trade.page.pay',
    'format': 'JSON',
    'return_url': "http://127.0.0.1:8001/pay/notify/",
    'notify_url': "http://127.0.0.1:8001/pay/notify/",
    'charset': 'utf-8',
    'sign_type': 'RSA2',
    'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
    'version': '1.0',
    'biz_content': json.dumps({
        'out_trade_no': xxx,
        'product_code': 'FAST_INSTANT_TRADE_PAY',
        'total_amount': xxx,
        'subject': "tracer payment"
    }, separators=(',', ':'))
}


# 获取待签名的字符串
unsigned_string = "&".join(["{0}={1}".format(k, params[k]) for k in sorted(params)])

# 签名 SHA256WithRSA(对应sign_type为RSA2)
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import decodebytes, encodebytes

# SHA256WithRSA + 应用私钥 对待签名的字符串 进行签名
private_key = RSA.importKey(open("files/应用私钥2048.txt").read())
signer = PKCS1_v1_5.new(private_key)
signature = signer.sign(SHA256.new(unsigned_string.encode('utf-8')))

# 对签名之后的执行进行base64 编码,转换为字符串
sign_string = encodebytes(signature).decode("utf8").replace('\n', '')

# 把生成的签名赋值给sign参数,拼接到请求参数中。

from urllib.parse import quote_plus
result = "&".join(["{0}={1}".format(k, quote_plus(params[k])) for k in sorted(params)])
result = result + "&sign=" + quote_plus(sign_string)

gateway = "https://openapi.alipaydev.com/gateway.do"
pay_url = "{}?{}".format(gateway, result)

最后,欢迎大家关注我的个人微信公众号 『小小猿若尘』,获取更多IT技术、干货知识、热点资讯