轻松上手Python支付宝在线支付
windows系统安装Python虚拟环境
首先保证你的系统已经安装好了Python
安装virtualenv
C:\WINDOWS\system32>pip3 install virtualenvCollecting virtualenv Downloading virtualenv-15.1.0-py2.py3-none-any.whl (1.8MB) 100% |████████████████████████████████| 1.8MB 110kB/sInstalling collected packages: virtualenvSuccessfully installed virtualenv-15.1.0C:\WINDOWS\system32>
安装virtualenvwrapper
virtualenvwrapper是virtualenv的一个方便管理虚拟环境的管理器
pip3 install virtualenvwrapper
指定虚拟环境,保存路径
首先在要保存虚拟环境的地方创建一个Evns目录,然后将这个目录添加到系统环境变量,以后创建的虚拟环境就会保存在这个目录,重启系统后生效
创建虚拟环境,创建后会自动进入虚拟环境
mkvirtualenv 虚拟环境名称
[root@192 xu_ni_huan_jing]# mkvirtualenv jxiouUsing base prefix '/usr/local'New python executable in /usr/xu_ni_huan_jing/jxiou/bin/python3.5Also creating executable in /usr/xu_ni_huan_jing/jxiou/bin/pythonInstalling setuptools, pip, wheel...done.virtualenvwrapper.user_scripts creating /usr/xu_ni_huan_jing/jxiou/bin/predeactivatevirtualenvwrapper.user_scripts creating /usr/xu_ni_huan_jing/jxiou/bin/postdeactivatevirtualenvwrapper.user_scripts creating /usr/xu_ni_huan_jing/jxiou/bin/preactivatevirtualenvwrapper.user_scripts creating /usr/xu_ni_huan_jing/jxiou/bin/postactivatevirtualenvwrapper.user_scripts creating /usr/xu_ni_huan_jing/jxiou/bin/get_env_details(jxiou) [root@192 xu_ni_huan_jing]#
5.退出虚拟环境
deactivate
(jxiou) [root@192 xu_ni_huan_jing]# deactivate[root@192 xu_ni_huan_jing]#
6.查看有哪些虚拟环境
workon
[root@192 /]# workonjxiou2jxiou[root@192 /]#
7.进入一个指定的虚拟环境
workon jxiou(虚拟环境名称)
[root@192 /]# workon jxiou(jxiou) [root@192 /]#
8.虚拟环境创建好后,创建Django项目,创建好数据库,开始本地调试支付请求
支付宝接口集成 ,本地环境调试支付请求
1。首先登录 蚂蚁金服网站,也就是支付宝开发者平台
登录蚂蚁金服开发者平台后,创建沙箱应用
也就是支付宝给开发者提供的调试环境应用
注意这里我们一定选择RSA2(SHA256)密钥(推荐),这个是比较安全的方式,
2.我们设置应用公钥
设置公钥,访问https://docs.open.alipay.com/291/105971/ 这个网址
下载生成公钥的工具
下载解压后
生成公钥
生成公钥后会得到两个文件
注意:这两个文件很重要一定要保存好
生成公钥后,将公钥填写到信息配置里
当我们填写好公钥保存后,会自动给我们生成支付宝公钥
这样我们就有了3个秘钥
将3个秘钥修改成英文或者拼音名称后,放到网站项目中
在秘钥txt文件里,秘钥内容的头部和结尾加上两行字符串,注意所有秘钥都要加
3.支付宝,支付集成代码
#!/usr/bin/env python# -*- coding:utf8 -*-# pip install pycryptodome 需要模块加密方面的模块__author__ = 'bobby'from datetime import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Signature import PKCS1_v1_5from Crypto.Hash import SHA256from base64 import b64encode, b64decodefrom urllib.parse import quote_plusfrom urllib.parse import urlparse, parse_qsfrom urllib.request import urlopenfrom base64 import decodebytes, encodebytesimport jsonclass AliPay(object): """ 支付宝支付接口 """ def __init__(self, appid, app_notify_url, app_private_key_path, alipay_public_key_path, return_url, debug=False): self.appid = appid self.app_notify_url = app_notify_url self.app_private_key_path = app_private_key_path self.app_private_key = None self.return_url = return_url with open(self.app_private_key_path) as fp: self.app_private_key = RSA.importKey(fp.read()) self.alipay_public_key_path = alipay_public_key_path with open(self.alipay_public_key_path) as fp: self.alipay_public_key = RSA.import_key(fp.read()) if debug is True: self.__gateway = "https://openapi.alipaydev.com/gateway.do" else: self.__gateway = "https://openapi.alipay.com/gateway.do" def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs): biz_content = { "subject": subject, "out_trade_no": out_trade_no, "total_amount": total_amount, "product_code": "FAST_INSTANT_TRADE_PAY", # "qr_pay_mode":4 } biz_content.update(kwargs) data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url) return self.sign_data(data) def build_body(self, method, biz_content, return_url=None): data = { "app_id": self.appid, "method": method, "charset": "utf-8", "sign_type": "RSA2", "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "version": "1.0", "biz_content": biz_content } if return_url is not None: data["notify_url"] = self.app_notify_url data["return_url"] = self.return_url return data def sign_data(self, data): data.pop("sign", None) # 排序后的字符串 unsigned_items = self.ordered_data(data) unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items) sign = self.sign(unsigned_string.encode("utf-8")) ordered_items = self.ordered_data(data) quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in ordered_items) # 获得最终的订单信息字符串 signed_string = quoted_string + "&sign=" + quote_plus(sign) return signed_string def ordered_data(self, data): complex_keys = [] for key, value in data.items(): if isinstance(value, dict): complex_keys.append(key) # 将字典类型的数据dump出来 for key in complex_keys: data[key] = json.dumps(data[key], separators=(',', ':')) return sorted([(k, v) for k, v in data.items()]) def sign(self, unsigned_string): # 开始计算签名 key = self.app_private_key signer = PKCS1_v1_5.new(key) signature = signer.sign(SHA256.new(unsigned_string)) # base64 编码,转换为unicode表示并移除回车 sign = encodebytes(signature).decode("utf8").replace("\n", "") return sign def _verify(self, raw_content, signature): # 开始计算签名 key = self.alipay_public_key signer = PKCS1_v1_5.new(key) digest = SHA256.new() digest.update(raw_content.encode("utf8")) if signer.verify(digest, decodebytes(signature.encode("utf8"))): return True return False def verify(self, data, signature): if "sign_type" in data: sign_type = data.pop("sign_type") # 排序后的字符串 unsigned_items = self.ordered_data(data) message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items) return self._verify(message, signature)if __name__ == "__main__": """支付请求过程""" # 传递参数初始化支付类 alipay = AliPay( appid="2016080800192023", # 设置签约的appid app_notify_url="http://projectsedus.com/", # 异步支付通知url app_private_key_path=u"ying_yong_si_yao.txt", # 设置应用私钥 alipay_public_key_path="zhi_fu_bao_gong_yao.txt", # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, debug=True, # 默认False, # 设置是否是沙箱环境,True是沙箱环境 return_url="http://47.92.87.172:8000/" # 同步支付通知url ) # 传递参数执行支付类里的direct_pay方法,返回签名后的支付参数, url = alipay.direct_pay( subject="测试订单", # 订单名称 # 订单号生成,一般是当前时间(精确到秒)+用户ID+随机数 out_trade_no="201702021225", # 订单号 total_amount=100, # 支付金额 return_url="http://47.92.87.172:8000/" # 支付成功后,跳转url ) # 将前面后的支付参数,拼接到支付网关 # 注意:下面支付网关是沙箱环境, re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url) print(re_url) # 最终进行签名后组合成支付宝的url请求
4.生成支付URL后,我们用这个URL模拟支付一下
注意:沙箱环境,支付的时候要用沙箱账号里提供的支付账号才可以支付
支付成功后已经,跳转到我们设置的同步处理页面
5.支付宝支付成功后通过接口验证
#!/usr/bin/env python# -*- coding:utf8 -*-# pip install pycryptodome 需要模块加密方面的模块__author__ = 'bobby'from datetime import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Signature import PKCS1_v1_5from Crypto.Hash import SHA256from base64 import b64encode, b64decodefrom urllib.parse import quote_plusfrom urllib.parse import urlparse, parse_qsfrom urllib.request import urlopenfrom base64 import decodebytes, encodebytesimport jsonclass AliPay(object): """ 支付宝支付接口 """ def __init__(self, appid, app_notify_url, app_private_key_path, alipay_public_key_path, return_url, debug=False): self.appid = appid self.app_notify_url = app_notify_url self.app_private_key_path = app_private_key_path self.app_private_key = None self.return_url = return_url with open(self.app_private_key_path) as fp: self.app_private_key = RSA.importKey(fp.read()) self.alipay_public_key_path = alipay_public_key_path with open(self.alipay_public_key_path) as fp: self.alipay_public_key = RSA.import_key(fp.read()) if debug is True: self.__gateway = "https://openapi.alipaydev.com/gateway.do" else: self.__gateway = "https://openapi.alipay.com/gateway.do" def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs): biz_content = { "subject": subject, "out_trade_no": out_trade_no, "total_amount": total_amount, "product_code": "FAST_INSTANT_TRADE_PAY", # "qr_pay_mode":4 } biz_content.update(kwargs) data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url) return self.sign_data(data) def build_body(self, method, biz_content, return_url=None): data = { "app_id": self.appid, "method": method, "charset": "utf-8", "sign_type": "RSA2", "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "version": "1.0", "biz_content": biz_content } if return_url is not None: data["notify_url"] = self.app_notify_url data["return_url"] = self.return_url return data def sign_data(self, data): data.pop("sign", None) # 排序后的字符串 unsigned_items = self.ordered_data(data) unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items) sign = self.sign(unsigned_string.encode("utf-8")) ordered_items = self.ordered_data(data) quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in ordered_items) # 获得最终的订单信息字符串 signed_string = quoted_string + "&sign=" + quote_plus(sign) return signed_string def ordered_data(self, data): complex_keys = [] for key, value in data.items(): if isinstance(value, dict): complex_keys.append(key) # 将字典类型的数据dump出来 for key in complex_keys: data[key] = json.dumps(data[key], separators=(',', ':')) return sorted([(k, v) for k, v in data.items()]) def sign(self, unsigned_string): # 开始计算签名 key = self.app_private_key signer = PKCS1_v1_5.new(key) signature = signer.sign(SHA256.new(unsigned_string)) # base64 编码,转换为unicode表示并移除回车 sign = encodebytes(signature).decode("utf8").replace("\n", "") return sign def _verify(self, raw_content, signature): # 开始计算签名 key = self.alipay_public_key signer = PKCS1_v1_5.new(key) digest = SHA256.new() digest.update(raw_content.encode("utf8")) if signer.verify(digest, decodebytes(signature.encode("utf8"))): return True return False def verify(self, data, signature): if "sign_type" in data: sign_type = data.pop("sign_type") # 排序后的字符串 unsigned_items = self.ordered_data(data) message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items) return self._verify(message, signature)if __name__ == "__main__": """支付宝支付成功后通知接口验证""" # 接收支付宝支付成功后,向我们设置的同步支付通知url,请求的参数 return_url = 'http://47.92.87.172:8000/?total_amount=100.00×tamp=2017-10-11+22%3A44%3A17&sign=dHW%2F25EDd%2BYKqkU5krhseDNIOEyDpdJzSAaoqhTC0nlv8%2FEmrQVd0WqgGK0CS8Pax8sK4jIOdGLFa6lQEbIfzvH3Na2W949yCAYX04JL1Bi02wog7a8L7vfW9Kj%2BjfTQxumGH%2B1Drbezdg9gKOx3tX0cb1yBBdfifK6l1%2BE5UjggGbY60F6SD8A8XI06NMWb4ViU%2FLYtBhwAwU2koy1IK2%2BtBJM1xYFuBRlcWF61xCxexHwO0WEA3AwVRW1miuJjOpGiBTOwPI9Huj0WhkyRebIjBhSxReJdZIdTfAgwj4oqo4jAJCHDa6DKBM0H3wjKKXSyMeMBGKQB0Uv2rNdyng%3D%3D&trade_no=2017101121001004320200174640&sign_type=RSA2&auth_app_id=2016080800192023&charset=utf-8&seller_id=2088102170418468&method=alipay.trade.page.pay.return&app_id=2016080800192023&out_trade_no=201702021227&version=1.0' # 将同步支付通知url,传到urlparse o = urlparse(return_url) # 获取到URL的各种参数 query = parse_qs(o.query) # 定义一个字典来存放,循环获取到的URL参数 processed_query = {} # 将URL参数里的sign字段拿出来 ali_sign = query.pop("sign")[0] # 传递参数初始化支付类 alipay = AliPay( appid="2016080800192023", # 设置签约的appid app_notify_url="http://projectsedus.com/", # 异步支付通知url app_private_key_path=u"ying_yong_si_yao.txt", # 设置应用私钥 alipay_public_key_path="zhi_fu_bao_gong_yao.txt", # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, debug=True, # 默认False, # 设置是否是沙箱环境,True是沙箱环境 return_url="http://47.92.87.172:8000/" # 同步支付通知url ) # 循环出URL里的参数 for key, value in query.items(): # 将循环到的参数,以键值对形式追加到processed_query字典 processed_query[key] = value[0] # 将循环组合的参数字典,以及拿出来的sign字段,传进支付类里的verify方法,返回验证合法性,返回布尔值,True为合法,表示支付确实成功了,这就是验证是否是伪造支付成功请求 print(alipay.verify(processed_query, ali_sign))# 如果别人伪造支付成功请求,它不知道我们的支付宝公钥,伪造的就无法通过验证,测试可以将支付宝公钥更改一下,在验证就会失败,别忘了改回来
远程测试支付成功后返回服务器验证
首先准备一台服务器,将开发环境和项目同步到服务器上,并且在服务器上配置好python虚拟环境和所需python插件包
项目同步到服务器上,也就是将本地项目,上传到服务器进行同步
配置服务器信息
上传项目
数据上传后,在服务器配置数据库访问权限,和配置python环境
配置远程调试
1,在阿里云后台,开放8000端口
2,在服务器开发8000端口
vim /etc/sysconfig/iptables# Firewall configuration written by system-config-firewall# Manual customization of this file is not recommended.*filter:INPUT ACCEPT [0:0]:FORWARD ACCEPT [0:0]:OUTPUT ACCEPT [0:0]-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT-A INPUT -p icmp -j ACCEPT-A INPUT -i lo -j ACCEPT-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT#添加配置项-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT-A INPUT -m state --state NEW -m tcp -p tcp --dport 8000 -j ACCEPT-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT-A INPUT -j REJECT --reject-with icmp-host-prohibited-A FORWARD -j REJECT --reject-with icmp-host-prohibitedCOMMIT
重启防火墙
service iptables restart
设置当前,使用的数据库用户,可以任意ip访问
让数据库用户可以从外部登陆和本地登陆
grant all privileges(除授权外的所有权限) on *.*(表示所有数据库的所有表) to 'test_user(授权的用户名)'@'localhost(授权ip)' identified by 'test_user(用户密码)';
grant all privileges on *.* to 'test_user'@'localhost' identified by 'test_user';
grant all privileges(除授权外的所有权限) on *.*(表示所有数据库的所有表) to 'test_user(授权的用户名)'@'%(所有ip)' identified by 'test_user(用户密码)';
grant all privileges on *.* to 'test_user'@'%' identified by 'test_user';
配置项目的settings.py文件
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', #配置数据库引擎名称 'NAME': 'jxiou', #数据库名称 'USER': 'test_user', #数据库用户名 'PASSWORD': 'test_user', #数据库密码 'HOST': '47.52.39.160', #数据库链接地址,为服务器ip 'PORT': '3306', #数据库端口 }}
# SECURITY WARNING: don't run with debug turned on in production!DEBUG = TrueALLOWED_HOSTS = ['*'] # 允许任意ip访问项目
开始远程调试
此时,就可以用服务器ip加8000端口,访问服务器网站了
前面,我们在本地调试了支付宝支付请求,这下我们要调试,支付宝支付成功后向我们服务器返回请求我们要验证返回的请求,,所以需要将远程服务器启动来,接收支付宝的返回
settings.py
import os# Build paths inside the project like this: os.path.join(BASE_DIR, ...)BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 支付宝目录路径设置ying_yong_si_yao = os.path.join(BASE_DIR, 'app1/alipay/ying_yong_si_yao.txt')zhi_fu_bao_gong_yao = os.path.join(BASE_DIR, 'app1/alipay/zhi_fu_bao_gong_yao.txt')
urls.py
views.py
#!/usr/bin/env python# -*- coding:utf8 -*-from django.shortcuts import render# Create your views here.from django.shortcuts import render,HttpResponsefrom django.views.decorators.csrf import csrf_exempt,csrf_protectfrom app1.alipay.alipay import AliPayfrom jxiou.settings import ying_yong_si_yao, zhi_fu_bao_gong_yao@csrf_exemptdef alipaview(request): if request.method == "GET": processed_dict = {} # 接收支付宝传递参数 for key, value in request.GET.items(): # 循环参数 processed_dict[key] = value # 将参数添加到字典 sign = processed_dict.pop('sign', None) # 单独拿出sign字段 # 传递参数初始化支付类 alipay = AliPay( appid="2016080800192023", # 设置签约的appid app_notify_url="http://47.52.39.160:8000/alipa/", # 异步支付通知url app_private_key_path=ying_yong_si_yao, # 设置应用私钥 alipay_public_key_path=zhi_fu_bao_gong_yao, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, debug=True, # 默认False, # 设置是否是沙箱环境,True是沙箱环境 return_url="http://47.52.39.160:8000/alipa/" # 同步支付通知url,跳转地址 ) # 验证支付宝返回的合法性 yan_zhen = alipay.verify(processed_dict, sign) if yan_zhen is True: # 判断如果合法 out_trade_no = processed_dict.get('out_trade_no', None) # 商户订单号 trade_no = processed_dict.get('trade_no', None) # 支付宝交易号 buyer_id = processed_dict.get('buyer_id', None) # 买家支付宝用户号 trade_status = processed_dict.get('trade_status', None) # 交易状态 total_amount = processed_dict.get('total_amount', None) # 订单金额 receipt_amount = processed_dict.get('receipt_amount', None) # 实收金额 subject = processed_dict.get('subject', None) # 订单标题 gmt_payment = processed_dict.get('gmt_payment', None) # 交易付款时间 # 数据库操作 print(out_trade_no) print(trade_no) print(buyer_id) print(trade_status) print(total_amount) print(receipt_amount) print(subject) print(gmt_payment) # 向支付宝返回success,告诉他我们已经处理,不然他会不停的通知 return HttpResponse('success') if request.method == "POST": # post请求支付宝异步通知 processed_dict = {} # 接收支付宝传递参数 for key, value in request.POST.items(): # 循环参数 processed_dict[key] = value # 将参数添加到字典 sign = processed_dict.pop('sign', None) # 单独拿出sign字段 # 传递参数初始化支付类 alipay = AliPay( appid="2016080800192023", # 设置签约的appid app_notify_url="http://47.52.39.160:8000/alipa/", # 异步支付通知url app_private_key_path=ying_yong_si_yao, # 设置应用私钥 alipay_public_key_path=zhi_fu_bao_gong_yao, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, debug=True, # 默认False, # 设置是否是沙箱环境,True是沙箱环境 return_url="http://47.52.39.160:8000/alipa/" # 同步支付通知url ) # 验证支付宝返回的合法性 yan_zhen = alipay.verify(processed_dict, sign) if yan_zhen is True: # 判断如果合法 out_trade_no = processed_dict.get('out_trade_no', None) # 商户订单号 trade_no = processed_dict.get('trade_no', None) # 支付宝交易号 buyer_id = processed_dict.get('buyer_id', None) # 买家支付宝用户号 trade_status = processed_dict.get('trade_status', None) # 交易状态 total_amount = processed_dict.get('total_amount', None) # 订单金额 receipt_amount = processed_dict.get('receipt_amount', None) # 实收金额 subject = processed_dict.get('subject', None) # 订单标题 gmt_payment = processed_dict.get('gmt_payment', None) # 交易付款时间 # 数据库操作 print(out_trade_no) print(trade_no) print(buyer_id) print(trade_status) print(total_amount) print(receipt_amount) print(subject) print(gmt_payment) # 向支付宝返回success,告诉他我们已经处理,不然他会不停的通知 return HttpResponse('success')
WAIT_BUYER_PAY 交易创建,等待买家付款TRADE_CLOSED 未付款交易超时关闭,或支付完成后全额退款TRADE_SUCCESS 交易支付成功TRADE_FINISHED 交易结束,不可退款
用户评论
这游戏标题听起来像是教学资源,而不是游戏本身啊!不过,如果真的有游戏的话,应该会很有趣。
有17位网友表示赞同!
支付宝支付在游戏中实现,听起来像是结合了金融和技术的元素,挺有创意的。
有9位网友表示赞同!
如果这款游戏真的存在,那对于编程新手来说是个不错的入门游戏。
有10位网友表示赞同!
商家说人傻了,难道是在说游戏太难了?哈哈。
有18位网友表示赞同!
学编程的同时还能体验支付宝支付,这种游戏形式挺新鲜的。
有5位网友表示赞同!
如果这个游戏是免费的,那学编程的同时还能省钱,太棒了。
有19位网友表示赞同!
Python是编程界的宠儿,支付宝也是支付界的巨头,两者结合的游戏肯定不简单。
有6位网友表示赞同!
这款游戏的名字太有意思了,让人忍不住想一探究竟。
有12位网友表示赞同!
商家这个反应有点逗,也许是因为游戏难度太高了。
有12位网友表示赞同!
如果是教学游戏,那应该会包含很多实战案例,对开发者很有帮助。
有6位网友表示赞同!
Python编程加支付宝支付,这样的游戏设计很有前瞻性。
有19位网友表示赞同!
对于支付宝用户来说,这款游戏可能会让他们对支付过程有更深入的了解。
有9位网友表示赞同!
这款游戏如果出了,我一定要试试,看看能不能成为编程高手。
有14位网友表示赞同!
商家这个反应太可爱了,期待这款游戏能早日上线。
有10位网友表示赞同!
如果游戏有互动教学,那应该能更好地帮助玩家掌握Python和支付宝支付。
有12位网友表示赞同!
这种结合实际应用场景的游戏,学起来肯定更有动力。
有13位网友表示赞同!
这款游戏如果成功,可能会成为编程教育的利器。
有19位网友表示赞同!
希望游戏能提供一个详细的教程,让新手也能轻松上手。
有6位网友表示赞同!