目录
django支付宝支付
新建支付宝应用
# 访问"支付宝开发平台"登录,可以访问开发者中心
https://open.alipay.com/platform/home.htm
# 可以参考"电脑网站支付" 熟悉电脑支付整体流程
https://docs.open.alipay.com/270/105899/
创建应用(使用沙箱环境测试)
- 沙箱环境说明
- 线上环境需要创建应用,因为我们不是企业,没有资质,所以只能申请沙箱环境
- 简单来讲沙箱环境就是给开发者使用的测试环境
- 沙箱环境地址: https://openhome.alipay.com/platform/appDaily.htm?tab=info
按照官方要求生成私钥(可以上支付宝开发平台下载支付宝开发助手)
把生成的app公钥粘贴到沙箱的app中
沙箱环境地址: https://openhome.alipay.com/platform/appDaily.htm?tab=info
查看沙箱账号和密码
支付宝开发地址
支付宝开放平台: https://open.alipay.com/platform/home.htm
支付宝沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info
支付宝开发者文档:https://openhome.alipay.com/developmentDocument.htm
电脑网站支付流程:https://docs.open.alipay.com/270
生成签名:https://docs.open.alipay.com/291/106103/
python-alipay-adk : https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
说明
- 阿里官方没有提供python对接支付的sdk,但是python库中有非官方的sdk包可以使用
- python-alipay-adk : https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
- 使用起来非常简单,只要传入几个必要的参数就可以完成
- 由于支付对安全要求很高,所以要理解对接支付宝安全的流程: 公钥加密、私钥解密 这八个字
在utils中封装请求支付宝扫码地址url的函数和生成订单id的函数
私钥和公钥可以放在app_private_key.pem 和 alipay_public_key.pem文件中。使用时引入
沙箱环境中 app 私钥
private_key_string= open('app_private_key.pem').read()
支付宝公钥
public_key_string = open( 'alipay_public_key.pem').read()
# -*- coding: utf-8 -*-
import datetime
import os
import random
from alipay import AliPay
private_key_string = '''-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApNZyqxPGS3xs/p6lpgffgnbvELjReMRz3y2WGhynDeY/vwODsafKy7XDvYPvE6iGXegz4vxtJINOBJprPXqamQvPJq20z/R3CZlCsOEy75Pr77ZRGZbMvzVXGkuavnLQoH40FuRbQYMXt8rLR1GnBS+5Bs5tWNfy94f4x4VroEZ80zVDnQEkzy46fmoi6lZ5r6N/7iXFo0fXdFWlvZJ0EDBF0BdSnHz7nSi6gbAix+VRU2mhyxh/C3ziF8GSuffzfolPORAKj/ws/UCLyBEio6OR0LJPPiulEEYR1cOsm784GHqCh+7C8MWoRmF1UWZ7nwVR+87Ezaq+ksxLxlKwYwIDAQABAoIBACc0RdOAgYIEltu8GcP2Lx1MnO+CNXfWqYRkEDYnqGe64mBo0pKXSLlIgsR5M4xmYYbGKkkLJl4vyId5vpXBqjFKSLt3RvDKwOEMjXsKJJYshUne/8zpO8siQZQkdSpknk/9lB/5seaT6jkxR0WwGtw17Hi88e7WdZf/w+CYT++vUNDR3thzhGSzgXvfrWppP4XMDnW75HJY+MgRo591vsbLwuQgEMTRqaroU1i5+ivDRak6KhKsiJ3QKJYUO1a+0AUTZMuoOo1Vhyn1qYiaRASYov73vK0WZDLd5/K8anBxWXKVwxj5IBivXcotrlaEQzvvcdu/HxH6+WT4VKQHq5kCgYEA9VFat/q6hGGoSgP3byl2ZbqohoEB2dGFGwgoXKGt8wO2tLhJCAGeyU4uLRAGTk6eO9qnAVr7ZsGmEQ1yaMOwRmatJLZze9yjQufkKOkInrXvVUebXdvRmeUtJ4l0NqtrmkrNcJw49HNR0pjSOhN6R9BGUd75l/P/hU3yjoFF7n0CgYEArAPz8UDYvq1ZKico2vjrWIrnsDpvDsgx8L+i73LzKrL9B3ZTimW+7wsIcWhQF1s27qMnQFPjKbEuqWOTi92TbV7BYXbAyQND0V+y0Txbfs54rGwB2A+0kVTP+sLA/x0mqnek3P2gAsl4p9A5A37rNGESgM64hLd5NOauH60S8F8CgYAixyzQRf2txNaB37wVY1BoraS0pNdpVN3E7kwijb1GZXFif3nDC8/CBDZhpxLtyRF/tMjWVVqsv6lWY4yjs5Jq+KV1PfRzS91NX+ilsBvLvEk40tUA4mf9pFLZdxAlq/muPwqO+2bLqQmheI7JMvez9J/zfWPvGeVQtbM8ZrFOVQKBgQCY+nr8V5trGGdv4ZuoAi/rcr1SMOWL0+b2ILgbE7PGiaAV/tmU/5+qn7lGgmqYGvrjiB3kS7Z+4aCJ7JDPlqMCZX692wrguhKaJe21v2Pvhlgzn2qUaINBrJe6f3F8cMRuXjE0iCrBz8OKGthZj4pF7v6xpybagQE+VtkMOrPZKQKBgDQh5Q4510y+ta+mFPb3tum4cXKBAUeRTS6+Us/0wvNVGpvnPGKzIcP+rGXlAO0Nl7O/PTBgejcIILjcS9AuyxPSfSWhlt5DjjzeQ8/J4yrgVAwQeNC28jkmnKBe5K3R+++Si++nYq4/nZ1WEyyginFf2nvQrW2G+rkzMOKvtRn/
-----END RSA PRIVATE KEY-----'''
publice_key_string = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNZyqxPGS3xs/p6lpyVImg1XELjReMRz3y2WGhynDeY/vwODsafKy7XDvYPvE6iGasegz4vxtJINOBJprPXqamQvPJq20z/R3CZlCsOEy75Pr77ZRGZbMvzVXGkuavnLQoH40FuRbQYMXt8rLR1GnBS+5Bs5tWNfy94f4x4VroEZ80zVDnQEkzy46fmoi6lZ5r6N/7iXFo0fXdFWlvZJ0EDBF0BdSnHz7nSi6gbAix+VRU2mhyxh/C3ziF8GSuffzfolPORAKj/ws/UCLyBEio6OR0LJPPiulEEYR1cOsm784GHqCh+7C8MWoRmF1UWZ7nwVR+87Ezaq+ksxLxlKwYwIDAQAB
-----END PUBLIC KEY-----'''
# udbble1952@sandbox.com
## 获取支付宝url
def get_alipay_url(order_id, order_amount, subject):
alipay = AliPay(
appid="888888888888", # 沙箱appid
app_notify_url=None, # 默认回调url
app_private_key_string=private_key_string,
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_string=publice_key_string,
sign_type="RSA2", # RSA 或者 RSA2
debug=True, # 默认False,我们是沙箱,所以改成True(让访问沙箱环境支付宝地址)
)
# 调用支付接口
# 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=order_id, # 订单id,应该从前端获取生成链接地址如下
total_amount=str(order_amount), # 订单总金额
subject=subject, # 付款标题信息
return_url='http://127.0.0.1:8888/payment/callback/', # 付款成功回调地址(可以为空)
notify_url=None # 付款成功后异步通知地址(可以为空)
)
pay_url = "https://openapi.alipaydev.com/gateway.do?" + order_string
return pay_url # 将这个url复制到浏览器,就会打开支付宝支付页面
# 获取订单唯一id
def get_order_id():
"""
SYL202008241212121200005/24
生成订单号: 格式: SYL + 年月日时分秒 + 5位随机数
:return:
"""
d = datetime.datetime.now()
base = 'SYL'
time_str = '%04d%02d%02d%02d%02d%02d' % (d.year, d.month, d.day, d.hour,
d.minute, d.second)
# 1.4 syl/setings.py中配置支付相关参数
# 2.测试
# 请求地址
# 携带参数
# 返回数据
rand_num = str(random.randint(10000, 99999))
return base + time_str + rand_num
在model.py中定义表
from django.db import models
from utils.MyBaseModel import Base
# Create your models here.
# 商品表
class Goods(Base):
GOODS_TYPE = (
("1", "vip"),
("2", "Course")
)
CHANNEL_TYPE = (
("1", "普通"),
("2", "促销")
)
course = models.OneToOneField('course.Course', on_delete=models.PROTECT)
goods_type = models.CharField("商品种类", choices=GOODS_TYPE, max_length=8)
product_id = models.CharField("产品id", max_length=8)
title = models.CharField("商品名称", max_length=24)
price = models.DecimalField("商品价格", max_digits=8, decimal_places=2)
channel_type = models.CharField("购买渠道", choices=CHANNEL_TYPE, max_length=8)
period = models.IntegerField("有效期", default=365)
is_launched = models.BooleanField("是否上架", default=True)
class Meta:
db_table = "tb_goods"
def __str__(self):
return self.title
# 订单表
class Orders(Base):
PAY_METHOD = (
("1", "支付宝"),
)
ORDER_STATUS = (
("1", "待支付"),
("2", "已支付"),
("3", "已取消")
)
user = models.ForeignKey('user.User', on_delete=models.PROTECT, verbose_name="下单用户")
goods = models.ForeignKey(Goods, on_delete=models.PROTECT)
order_id = models.CharField("订单号", max_length=24)
trade_no = models.CharField("支付订单号", max_length=32, null=True)
pay_time = models.DateTimeField("支付时间", null=True)
pay_method = models.CharField("支付方式", choices=PAY_METHOD, default=1, max_length=8)
status = models.CharField("支付状态", choices=ORDER_STATUS, default=1, max_length=8)
total_amout = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
class Meta:
db_table = "tb_orders"
def __str__(self):
return self.order_id
# 用户购买课程表
class UserCourse(Base):
user = models.ForeignKey('user.User', on_delete=models.CASCADE)
course = models.ForeignKey('course.Course', on_delete=models.CASCADE)
class Meta:
db_table = "usercourse"
def __str__(self):
return "用户%s购买的%s" % (self.user, self.course)
在views.py中获取支付宝支付的url的接口和回调接口
from decimal import Decimal
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Goods, Orders, UserCourse
from .serializers import GoodsModelSer, OrdersModelSer
from .util import get_order_id, get_alipay_url
from course.models import Course
# 获取支付宝扫码页面的url
class Get_Pay_url(APIView):
def post(self,request):
# 根据前端发送的商品id获取对应的商品信息
goods_id = request.data.get("goods_id")
goods_obj = Goods.objects.get(pk=goods_id)
# 获取用户信息
user = request.user
# 判断用户的身份对应进行打折
if user.vip.vip_type == "3":
goods_price = (goods_obj.price * Decimal('0.60')).quantize(Decimal('0.00'))
elif user.vip.vip_type == "2":
goods_price = (goods_obj.price * Decimal('0.80')).quantize(Decimal('0.00'))
else:
goods_price = goods_obj.price
# 存入数据库
order = Orders(
user= user,
goods= goods_obj,
order_id= get_order_id(), # 调用在util.py中写的函数获取商品订单id
pay_method= 1,
status= 1,
total_amout= goods_price,
)
order.save()
subject = "实验楼订单:%s,价格:%s" % (order.order_id, goods_price)
# 调用util中的获取支付宝路由的函数并把自己生成的订单id
pay_url = get_alipay_url(order_id=order.order_id, order_amount=order.total_amout, subject=subject)
return Response({"code":200, "msg": "成功", "data": {"pay_url": pay_url}})
"""
# 前端回调返回的数据
{ "charset": "utf-8",
"out_trade_no": "SYL2020101508522512986", # 我们自己生成的订单id
"method": "alipay.trade.page.pay.return",
"total_amount": "100.00", # 支付价格
"sign": "HFfe2xBFw/jY8XaJdzuUnqWg9+wPS/PdH7GGigNRScVhfxF94lm2id1eURP/TdvWs4F2HRukJ0Rf/UNzrz4QG18EKiT68ChGrZvIiZHaONY2ok/ix5r68IkQM/7yCB+YF4NrkHDuw92Iy7mLrdKNkOan3+uLgocNuWDTNWo4hT5gCFTxOPPrrWDSJmanX3RPI6HrLsOWUpTcZjhQafAKK0S6Y+bl+MtgfLPV7+hcMesItb/pvsHDRPD1j63VkGuP2mXwW3eDCns3LCn1YfWqjwmutXGqbLEK0HG9NgOKFBL9N6+lBE2lJqfdSo79vMY9cv7287ZvC1b07cygLXMVDA==",
"trade_no": "2020101522001458970501542142", # 支付宝的支付id
"auth_app_id": "2016103000778269",
"version": "1.0",
"app_id": "2016103000778269",
"sign_type": "RSA2",
"seller_id": "2088102181451641",
"timestamp": "2020-10-15 16:52:56" # 支付时间
}
"""
# 支付宝回调地址
class PeyMent(APIView):
def post(self, request):
# 获取前端发送的数据
order_id = request.data.get("out_trade_no") # 自己生成的订单id
trade_no = request.data.get("trade_no") # 支付宝返回的支付宝订单id
pay_time = request.data.get("timestamp") # 创建时间
# 根据订单id获取到对应的订单信息
orders = Orders.objects.get(order_id=order_id)
# 修改订单状态,支付时间,支付宝的订单id
orders.trade_no = trade_no
orders.pay_time = pay_time
orders.status = 2
orders.save()
# 根据订单获取到对应的商品然后获取到对应的课程
course_obj = Course.objects.get(pk=orders.goods.course_id)
# 存到用户购买课程表中
user = UserCourse(user=request.user, course=course_obj)
user.save()
return Response({"code":200, "msg": "支付成功"})
前端vue
生成订单, 获取支付链接
// 生成订单, 获取支付链接
pay() {
// goods_id: 课程id
payurl_post({ goods_id: this.goods.id }).then((resp) => {
console.log(resp)
let pay_url = resp.data.pay_url
// debugger
window.location = pay_url
})
},
回调页面
<template>
<div>
这里是支付回调地址, 把数据发送给后端
参数是:
{{query}}
<p>
支付结果是: {{msg}}
</p>
</div>
</template>
<script>
import { payment_post } from './axios_api/api';
export default {
data() {
return {
query: '',
msg: '', //支付结果
}
},
mounted() {
this.query = this.$route.query
payment_post(this.query).then((resp) => {
// ({"code": 999, "msg": "非法请求"})
this.msg = resp.msg
})
},
}
</script>