博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
django实现支付宝支付
阅读量:4449 次
发布时间:2019-06-07

本文共 13708 字,大约阅读时间需要 45 分钟。

1.沙箱环境

  蚂蚁沙箱环境(Beta)是协助开发者进行接口功能开发及主要功能联调的辅助环境。沙箱环境模拟了开放平台部分产品的主要功能和主要逻辑。

  在开发者应用上线审核前,开发者可以根据自身需求,先在沙箱环境中了解、组合和调试各种开放接口,进行开发调通工作,从而帮助开发者在应用上线审核完成后,能更快速、更顺利的进行线上调试和验收工作。

  详细介绍---->

1.1配制沙箱环境

  登录,点击自研开发者,点击导航的开发者中心-->研发服务,填写相关信息,完成实名认证

  点击“开放平台-开发者中心-”。进入沙箱环境页面,系统已经自动为你创建一个应用,在基础信息中可以看到应用信息

  点击查看应用公钥,设置应用公钥,点击查看秘钥生成方法

 

 

  下载windows版

  下载该工具后,解压打开文件夹,运行“RSA签名验签工具.bat”(WINDOWS)------>采用默认的格式

 

  使用2048位,.点击 “生成密钥”,点击“打开密钥文件路径”,即可找到生成的公私钥

  生成的私钥需妥善保管,避免遗失,不要泄露。应用私钥需填写到代码中供签名时使用。应用公钥需提供给支付宝账号管理者上传到支付宝开放平台。

  打开应用公钥2048.txt,将里面的内容复制一下进入到输入应用公钥的页面,输入公钥,点击保存。

2.SDK获取(software development kit)

  中文名称软件开发工具,第三方服务商提供的实现软件铲平某项功能的工具包,一般以kpi和文档,范例的形式出现

  这里注意的是,支付宝使用了rsa加密算法,这是支付宝独有的加密方式,我们使用了它的SDK之后,不要关心是如何加密的,只需要按照它的逻辑部署即可

  获取连接------->

 

这里使用的是SDK封装好的一个python文件,需要安装pycryptodome,依赖该加密模块。文件是从GitHub上获取到的,为第三方提供

目前支付宝官方还不提供SDK,如上

pip3 install pycryptodome

pay.py代码   ---->后期需要部署到django中(github中获取的SDK)

from datetime import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Signature import PKCS1_v1_5from Crypto.Hash import SHA256from urllib.parse import quote_plusfrom urllib.parse import urlparse, parse_qsfrom base64 import decodebytes, encodebytesimport jsonclass AliPay(object):    """    支付宝支付接口(PC端支付接口)    """    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.importKey(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 unsigned_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)

3.项目部署

启动我们的django程序,创建相关的文件夹用于存放相关文件

## 需要说明的是,为了显示友好,我们需要把公钥和私钥名称进行修改,我这里改成了alipay_public_2048.txt和app_private_2048.txt

## 还有,对于公钥文件和私钥文件需要增加头部和尾部

公钥文件:

-----BEGIN PUBLIC KEY-----KEY...-----END PUBLIC KEY-----

私钥文件:

-----BEGIN RSA PRIVATE KEY-----KEY...-----END RSA PRIVATE KEY-----

django:

models.py  --->自行启动添加数据

from django.db import modelsclass Goods(models.Model):    name = models.CharField(max_length=32)    price = models.FloatField()class Order(models.Model):    no = models.CharField(max_length=64)    goods = models.ForeignKey(to='Goods',on_delete=models.CASCADE)    status_choices = (        (1,'未支付'),        (2,'已支付'),    )    status = models.IntegerField(choices=status_choices,default=1)
View Code

urls.py

from django.contrib import adminfrom django.urls import path,re_pathfrom app01 import viewsurlpatterns = [    path('admin/', admin.site.urls),    path('index/',views.index),    re_path('buy/(?P
\d+)',views.buy), path('check_order',views.check_order), path('show/',views.show), path('order_list',views.order_list),]
View Code

utils/pay.py   --->我们的SDK

from datetime import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Signature import PKCS1_v1_5from Crypto.Hash import SHA256from urllib.parse import quote_plusfrom urllib.parse import urlparse, parse_qsfrom base64 import decodebytes, encodebytesimport jsonclass AliPay(object):    """    支付宝支付接口(PC端支付接口)    """    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.importKey(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 unsigned_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)
View Code

views.py    --->注意实例化的时候,给我们的SDK发送的信息

import uuidfrom app01 import modelsfrom utils import payfrom django.shortcuts import render,HttpResponse,redirectdef index(request):    """    商品页面    """    good_list = models.Goods.objects.all()    return render(request,"index.html",{
"goods_list":good_list})def buy(request,ids): """ 购买,支付 """ # 获取用户购买的物品对象 obj = models.Goods.objects.get(id=ids) # 对生成订单加密,并添加进入数据库 no = str(uuid.uuid4()) models.Order.objects.create(no=no,goods_id=obj.id) # 全局变量 alipay = pay.AliPay( appid="2016091700529011", # 注意,改成自己的,在支付宝沙箱环境中 app_notify_url="http://127.0.0.1:8000/check_order/", # POST,发送支付状态信息 return_url="http://127.0.0.1:8000/show/", # GET,将用户浏览器地址重定向回原网站 app_private_key_path="key/app_private_2048.txt", alipay_public_key_path="key/alipay_public_2048.txt", debug=True, # 默认True测试环境、False正式环境 ) query_params = alipay.direct_pay( subject=obj.name, out_trade_no=no, # 商品订单号 total_amount=obj.price, # 交易金额(保留两位小数) ) # 支付宝提供的url网关 pay_url = "https://openapi.alipaydev.com/gateway.do?{0}".format(query_params) return redirect(pay_url)def check_order(request): """ POST请求,支付宝通知支付信息,我们修改订单状态 """ if request.method == 'POST': # 全局变量 alipay = pay.AliPay( appid="2016091700529011", # 注意,改成自己的,在支付宝沙箱环境中 app_notify_url="http://127.0.0.1:8000/check_order/", # POST,发送支付状态信息 return_url="http://127.0.0.1:8000/show/", # GET,将用户浏览器地址重定向回原网站 app_private_key_path="key/app_private_2048.txt", alipay_public_key_path="key/alipay_public_2048.txt", debug=True, # 默认True测试环境、False正式环境 ) from urllib.parse import parse_qs body_str = request.body.decode('utf-8') post_data = parse_qs(body_str) post_dict = {} for k,v in post_data.items(): post_dict[k] = v[0] sign = post_dict.pop('sign',None) status = alipay.verify(post_dict,sign) if status: # 支付成功 out_trade_no = post_dict['out_trade_no'] models.Order.objects.filter(no=out_trade_no).update(status=2) return HttpResponse("支付成功,(ノ`Д)ノ") else: return HttpResponse("支付失败,")def show(request): """ 回到我们的页面 """ if request.method == "GET": alipay = pay.AliPay( appid="2016091700529011", # 注意,改成自己的,在支付宝沙箱环境中 app_notify_url="http://127.0.0.1:8000/check_order/", # POST,发送支付状态信息 return_url="http://127.0.0.1:8000/show/", # GET,将用户浏览器地址重定向回原网站 app_private_key_path="key/app_private_2048.txt", alipay_public_key_path="key/alipay_public_2048.txt", debug=True, # 默认True测试环境、False正式环境 ) params = request.GET.dict() print(params) sign = params.pop('sign', None) status = alipay.verify(params, sign) if status: return HttpResponse('支付成功') else: return HttpResponse('失败') else: return HttpResponse('只支持GET请求')def order_list(request): """ 查看订单状态 """ order = models.Order.objects.all() return render(request,'order_list.html',{
'orders':order})
View Code

index.html

    
Title
    {% for row in goods_list %}
  • {
    { row.name }},价格:{
    { row.price }} 购买
  • {% endfor %}
View Code

order_list.html

    
Title
{% for item in orders %}
{% endfor %}
{
{ item.id }}
{
{ item.no }}
{
{ item.goods.name }}
{
{ item.get_status_display }}
View Code

4.测试支付(注意该接口目前只支持安卓用户支付)

  运行起来之后接入index页面,点击支付,会自动跳转到支付页面

 

转载于:https://www.cnblogs.com/LearningOnline/p/9458000.html

你可能感兴趣的文章
USACO 3.1 Contact
查看>>
Office之什么是高内聚低耦合
查看>>
一些奇怪的问题求回答
查看>>
这些年踩过的坑
查看>>
iOS开发拓展篇——如何把项目托管到GitHub
查看>>
性能优化之数据库优化
查看>>
类的继承、菱形继承、派生、多态
查看>>
mysql约束
查看>>
javascript鼠标及键盘事件总结及案例
查看>>
mysql表之间的关系及级联操作
查看>>
mac 搭建virtualenv的那些坑
查看>>
多路复用IO模型
查看>>
并发、串行、并行及多道技术原理
查看>>
hashlib、pickle、hmac、logging模块使用
查看>>
javascript常用知识点总结
查看>>
2019秋招复习笔记--数据库基本操作
查看>>
2019秋招复习笔试--手写代码
查看>>
2019秋招复习笔记--智力题
查看>>
MySQL学习笔记
查看>>
2019秋招面试复习 项目重点提问
查看>>