from django.db import models
class shopping(models.Model):
id = models.AutoField(primary_key=True)
shoping = models.CharField(max_length=64)
money = models.FloatField()
class order(models.Model):
id = models.AutoField(primary_key=True)
shopping = models.ForeignKey('shopping',to_field='id',on_delete=models.CASCADE)
status_choics = ((1,'未支付'),(2,'已支付'))
status = models.IntegerField(choices=status_choics,default=1)
pip3 install python-alipay-sdk --upgrade
在项目根目录下新建名为utils的文件夹,在这个新建的文件夹下面创建两个txt文件和一个py文件,将第一个txt文件改名为app_privatc_2048.txt,文件中的内容如下:
-----BEGIN RSA PRIVATE KEY-----
写上你的应用私钥
-----END RSA PRIVATE KEY-----
第二个txt文件改名为alipay_public_2048.txt,文件中的内容如下:
-----BEGIN PUBLIC KEY-----
写上你的支付宝公钥,支付宝公钥是由应用公钥生成的,在开放平台的沙箱环境下获取
-----END PUBLIC KEY-----
将py文件改名为alipay.py,内容如下:
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus
from base64 import decodebytes, encodebytes
import json
class 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)
python manage.py makemigrations
python manage.py migrate
# 支付宝公钥
alipay_public_key_path = os.path.join(BASE_DIR,'utils/alipay_public_2048.txt')
# 应用私钥
app_private_key_path = os.path.join(BASE_DIR,'utils/app_privatc_2048.txt')
from utils.alipay import AliPay
# 支付需要的各种参数
app_id = '2016101900720980'
# POST,发送支付状态信息
notify_url = 'http://服务器IP:端口/baoinfo/'
# GET,将用户浏览器地址重定向到原网站
return_url = 'http://服务器IP:端口/returnonline/'
alipay = AliPay(
appid = app_id,
app_notify_url = notify_url,
return_url = return_url,
app_private_key_path = app_private_key_path,
alipay_public_key_path = alipay_public_key_path, # 支付宝公钥,验证支付宝回传消息使用不是自己的公钥
debug=True, # 默认是False,Ture是沙箱环境
)
from django.urls import path,re_path
from pay import views
urlpatterns = [
# 订单列表
re_path(r'^index/$',views.index.as_view(),name='index/'),
# 发起支付
re_path(r'^onsetpay/(?P\d+)/$' ,views.onsetpay.as_view(),name='onsetpay/'),
# 支付宝通知信息,POST
re_path(r'^baoinfo/$',views.baoinfo.as_view(),name='baoinfo/'),
# 回到我们的网站,GET
re_path(r'^returnonline/$',views.returnonline.as_view(),name='returnonline/'),
# 支付成功
re_path(r'^sures/$',views.sures.as_view(),name='sures/'),
from django.shortcuts import render,HttpResponse,redirect
from django.views.generic import View
from pay.models import shopping
from pay import models
import uuid
from urllib.parse import parse_qs
from .settings import alipay
# 商品列表
class index(View):
def get(self,request):
shopping_obj = shopping.objects.all()
return render(request,'index.html',{
'shopping_obj':shopping_obj})
# 发起支付
class onsetpay(View):
def get(self,request,shopid):
''' 去购买并支付 '''
shop_obj = models.shopping.objects.get(id=shopid)
money = shop_obj.money
# 商户订单号
no = str(uuid.uuid4())
# 加载需要携带的商品信息
query = alipay.direct_pay(
subject=shop_obj.shoping,# 商品描述
out_trade_no=no, # 商户订单号
total_amount = money,# 交易金额
)
pay_url = 'https://openapi.alipaydev.com/gateway.do?{}'.format(query)
return redirect(pay_url)
# 支付宝通知信息,POST
class baoinfo(View):
def get(self,request):
return HttpResponse('只支持POST请求!')
def post(self,request):
# print('我是POST请求,',request.POST)
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]
print(post_dict)
sign = post_dict.pop('sign',None)
status = alipay.verify(post_dict,sign)
if status:
print('OK')
''' 支付成功,获取订单号将状态更新 '''
return HttpResponse('支付成功!')
else:
print('False')
return HttpResponse('支付失败!')
# 回到我们自己的网站
class returnonline(View):
def get(self,request):
params = request.GET.dict()
sign = params.pop('sign',None)
status = alipay.verify(params,sign)
if status:
print('GET成功')
return redirect('sures/')
else:
print('GET失败')
return HttpResponse('支付失败!')
class sures(View):
def get(self,request):
return render(request,'sures.html')
post = {
'gmt_create': '2020-07-14 08:55:52',
'charset': 'utf-8',
'gmt_payment': '2020-07-14 08:55:59',
'notify_time': '2020-07-14 08:55:59',
'subject': 'Pycharm会员',
'sign': 'BRTY0LbgmJ4rGDhRHYHs0xGs7E44Ipnh08XX56ejo+A15ExoAbIRBPNEYsXqXloSPFpU5NOGJSfed0gM2vP+ThXJYU1c4lJxsLV7'
'+gz1dOxyN7QcxRvHH3+8+h8HwjnP7rbb+BsCEyVu1oFqGGFqY7wCGEZwM6F+LYEFkyS5KFhcMOx3wN8IZeS1kyNiOwN3VZO2XMXV'
'qB/Sy/nNWzjfoa7WzpQwqVIXM5oau1Fmr2YpGWpHhLA56qrZaKrkJ9ykgNOBsPljq3zjso+WXWCJUrtyxgtA2VFkbiVIvQpTxJ8M'
'3MmNHjBIlXmtplBE+R2iunK1yAYSydCHBPzbjyY+Sw==',
'buyer_id': '2088102180558167',
'invoice_amount': '85.41',
'version': '1.0',
'notify_id': '2020071400222085559058160506415070',
'fund_bill_list': '[{"amount":"85.41","fundChannel":"ALIPAYACCOUNT"}]',
'notify_type': 'trade_status_sync',
'out_trade_no': 'fa22b276-b8a9-4fe6-90b1-00da1741c941',
'total_amount': '85.41',
'trade_status': 'TRADE_SUCCESS',
'trade_no': '2020071422001458160500843069',
'auth_app_id': '2016101900720980',
'receipt_amount': '85.41',
'point_amount': '0.00',
'app_id': '2016101900720980',
'buyer_pay_amount': '85.41',
'sign_type': 'RSA2',
'seller_id': '2088102180238098'
}
get = {
'charset': 'utf-8',
'out_trade_no': 'fa22b276-b8a9-4fe6-90b1-00da1741c941',
'method': 'alipay.trade.page.pay.return',
'total_amount': '85.41',
'sign': 'LcqlazbMGtMMxyDM3uhzsZgOsyjSTZ8K+VPHJhCE8s7gwr5xEfRGVR9QH8mirlfkZgX2biYoqYF0R5+rNQJ5TO1hy4jTzr1y1'
'UP6SVN5pzZPgQD403FkPOdQ87nWUIiXBi/Mkdjthx3jpDMznbzXkOspNYGKB8NGpoKEThoCdhfD/kvP8kzbKs25diKNoFZWPU'
'VKSgYdZU31ONFNEYh/5fqbJn1XGa2CuvGwxRSnVEkOJ5jGSNS5UgHnkT6N8hO0XJsqfH+QDd3e3T2DJwmCZgRGh/kDaZz4ZQP'
'8SFP0mR3Hmtvt27enlytrzzQmToFVvNP6Ir8yYJ/43b92fLanng==',
'trade_no': '2020071422001458160500843069',
'auth_app_id': '2016101900720980',
'version': '1.0',
'app_id': '2016101900720980',
'sign_type': 'RSA2',
'seller_id': '2088102180238098',
'timestamp': '2020-07-14 08:56:05'
}