支付宝支付---流程详解

👏👏👏

哈喽!大家好,我是【太阳打伞】,一位热爱分享各种技术的博主!😍😍😍

⭐【太阳打伞】的创作宗旨:每一条命令都亲自执行过,每一行代码都实际运行过,每一种方法都真实实践过,每一篇文章都良心制作过。✊✊✊

⭐【太阳打伞】的博客中所有涉及命令、代码的地方,除了提供图片供大家参考,另外会在图片下方提供一份纯文本格式的命令或者代码方便大家粘贴复制直接执行命令或者运行代码。🤝🤝🤝

⭐如果你对技术有着浓厚的兴趣,欢迎关注【太阳打伞】,欢迎大家和我一起交流。😘😘😘

❤️❤️❤️感谢各位朋友接下来的阅读❤️❤️❤️
 

流程图:

 !!!:效果内容在最下方,一定要看呀。

第一步:

登录支付宝,打开控制台,进入研发服务

 

 第二步:

进入沙箱,生成自己的私钥,支付宝公钥

将支付宝公钥和自己私钥存放到.txt文件中

 第三步:

拿到自己的支付宝沙箱应用id,和   买家账号:xxxxxxxxxxxx
                                                        登录密码111111
                                                        支付密码111111,

买家账号等到支付时使用!

第四步:

后端代码实现:

创建alipay.py文件

我采用的是Tornado框架实现的!!!


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 urllib.parse import urlparse, parse_qs
from base64 import decodebytes, encodebytes
import json
from tornado import httpclient


class AliPay:
    """
    支付宝支付接口(PC端支付接口)
    """


    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=True):
        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"

    # 商户订单号out_trade_no
    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)


    # 查询订单状态方法
    async def api_alipay_trade_query(self,out_trade_no=None,**kwargs):
            biz_content = {
                "out_trade_no": out_trade_no
            }
            biz_content.update(**kwargs)

            data = self.build_body("alipay.trade.query", biz_content)
            url = self.__gateway + "?" + self.sign_data(data)
            res = await httpclient.AsyncHTTPClient().fetch(url,method='GET',validate_cert=False,connect_timeout=30.0, request_timeout=30.0)
            res = json.loads(res.body.decode())
            return res

    #请求支付宝退款接口
    async def api_alipay_trade_refund(self, refund_amount, out_trade_no=None, trade_no=None, **kwargs):
            biz_content = {
                "refund_amount": refund_amount
            }
            biz_content.update(**kwargs)
            if out_trade_no:
                biz_content["out_trade_no"] = out_trade_no
            if trade_no:
                biz_content["trade_no"] = trade_no
            data = self.build_body("alipay.trade.refund", biz_content)
            url = self.__gateway + "?" + self.sign_data(data)
            res = await httpclient.AsyncHTTPClient().fetch(url,method='GET',validate_cert=False,connect_timeout=30.0, request_timeout=30.0)
            res = json.loads(res.body.decode())
            return res

    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)



第五步:

写pay.py主文件:

import datetime
import logging
import decimal
from base import BaseHandler
from tornado.web import url

from db import UserModel,OrderModel
from user import BaseMange
# 充值
from alipay import AliPay
from utils import jwt_auth

# 钱包
class WalletHandler(BaseMange):
    """创建订单"""

    @jwt_auth
    async def post(self):
        _where = "model.uid == {}".format(self._cuser.id)
        orders = await self.get_all_where(OrderModel,_where)
        return self.finish({"errcode":0,"data":orders})

    @jwt_auth
    async def get(self):
        # 查询用户余额
        user = await self.get_one_obj(UserModel, self._cuser.id)

        return self.finish({'errcode': 0, 'data': user.wallet})



class PayHandler(BaseMange):
    # 转跳地址
    @jwt_auth
    async def get(self):

        alipay = AliPay(
            appid='xxxxxxxxxx',  # 你的支付宝沙箱应用的id
            app_private_key_path='./keys/app_private_2048.txt',  # 你的私钥
            alipay_public_key_path='./keys/alipay_public_2048.txt',  # 支付宝公钥,
            app_notify_url="http://127.0.0.1:8080/wallet",  # 回调地址
            return_url='http://127.0.0.1:8080/pay',
            debug=True  # 请求来到支付宝沙箱)
        )
        # 3.创建订单
        order_id = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + "_%s" % self._cuser.id
        subject = self.get_argument("subject",None)
        # 订单编号
        total_amount= self.get_argument("total_amount",None)
        # res = alipay.direct_pay(subject,order_id,total_amount)
        # print(res)
        # pay_url = "https://openapi.alipaydev.com/gateway.do?"+res  # 支付宝网关地址(沙箱应用)
        # return self.finish({'errcode': 0, 'data': pay_url})

        """创建订单"""
        try:
            # 创建订单信息
            order = {"order_id": order_id, "uid_id": self._cuser.id, "total_amount": float(total_amount)}

            order = await self.create(OrderModel, order)
            res = alipay.direct_pay(subject, order_id, total_amount)
            print(res)
            pay_url = "https://openapi.alipaydev.com/gateway.do?" + res  # 支付宝网关地址(沙箱应用)
            # print(pay_url)
            return self.finish({'errcode': 0, 'data': pay_url})
        except Exception as e:
            logging.error("create order error, reason is %s" % e)
            return self.finish({'errcode': 1, 'msg': "交易出错!"})

    @jwt_auth
    async def post(self):

        order_id = self.get_argument("out_trade_no", None)  # 订单编号

        _where = "(model.order_id=='{}')".format(order_id)

        alipay = AliPay(
            appid='xxxxxxxxxx',  # 你的支付宝沙箱应用的id
            app_private_key_path='./keys/app_private_2048.txt',  # 你的私钥
            alipay_public_key_path='./keys/alipay_public_2048.txt',  # 支付宝公钥,
            app_notify_url="http://127.0.0.1:8080/wallet",  # 回调地址
            return_url='http://127.0.0.1:8080/pay',
            debug=True  # 请求来到支付宝沙箱)
        )

        res = await alipay.api_alipay_trade_query(out_trade_no=order_id)
        print(res)
        res = res['alipay_trade_query_response']

        if res['code'] == '10000':
            try:
                order = await self.get_one_where(OrderModel, _where)

                # 修改订单的状态
                order.trade_no = res['trade_no']
                order.total_amount = res['total_amount']
                order.status = 1
                order.record = res["send_pay_date"]
                await self.application.objects.update(order)
                user = await self.get_one_obj(UserModel, self._cuser.id)
                user.wallet = user.wallet + decimal.Decimal(res['total_amount'])

                await self.application.objects.update(user)
                return self.finish({'errcode': 0, 'msg': "充值成功"})
            except Exception as e:
                print(e)

                return self.finish({'errcode': 1, 'msg': "未找到订单交易!"})

        else:
            return self.finish({'errcode': 2, 'msg': "支付失败!"})


urlpatterns = [
    url('/pay/', PayHandler),
    url('/wallet/', WalletHandler),


]

第六步:

前端代码实现

我使用的是Vue.3

文件名是:wallet.vue


<template>
  <div class="container">
    <a-layout>
      <a-layout-sider>
        <mymenu></mymenu>
      </a-layout-sider>
      <a-layout>

            <h2>充值页面</h2>

            <h3>我的钱包</h3>

            <p>
                        <a-col :span="22">
                            <a-statistic title="钱包余额" :precision="2" :value= wallet />
                        </a-col>
                    </p>

                    <div class="components-input-demo-presuffix">
                        <h2>钱包充值</h2>

                        <p>请输入充值金额:
                            <a-input v-model:value="value" prefix="¥" suffix="RMB" placeholder="请输入充值金额" />
                        </p>
                        <p>
                            <a-button type="primary" @click="get_pay()">支付宝充值</a-button>&emsp;
                            <a-button type="">微信充值</a-button>
                        </p>
                    </div>
                    <p>用户订单表</p>
                    <p><table>
                        <tr>
                            <th>订单编号</th>
                            <th>创建时间</th>
                            <th>支付方式</th>
                            <th>备注</th>
                            <th>支付状态</th>
                        </tr>
                        <tr  v-for="(j,i) in orderlist" :key="i">
                        <td>{{j.order_id}}</td>
                        <td>{{j.create_time}}</td>
                        <td>{{j.pay_method}}</td>
                        <td>{{j.record}}</td>
                        <td v-if="j.status==0">待支付</td>
                        <td v-if="j.status==1">已支付</td>
                        <td v-if="j.status==3">已取消</td>
                        </tr>
                    </table></p>



                <!-- <a-button type="link" @click="pay">开始充值</a-button> 

                
                <a-modal v-model:visible="visible" title="充值" @ok="visible=false">

                充值金额:<a-input v-model:value="money" />

                <a-button type="link" @click="pay">开始充值</a-button>
                
                
                </a-modal> -->
            
    
         
      </a-layout>
    </a-layout>
  </div>
</template>

<script>
// 导入子组件
import mymenu from "./mymenu.vue";
import { message } from "ant-design-vue";

export default {
  data() {
    return {
      
      collapsed: false,
      selectedKeys: ["1"],
      visible:false,
      money:'',
      id:'',
      wallet:0,
      value:50,
      orderlist:[]

      
      
      
      
    };
  },

  //声明组件
  components: {
    mymenu,
  },
  methods: {

            pay(id){
            this.visible = true
            // this.id = id
    },


            // 充值请求

            get_pay() {
            this.myaxios(this.baseurl + "pay/", "get",{"subject":"钱包充值","total_amount":this.value}).then(data => {

                console.log(data);
                if (data.errcode === 0) {
                    window.location.href=data.data
                }

            });
        },

            get_wallet() {
            this.myaxios(this.baseurl + "wallet/", "get").then(data => {

                console.log(data);
                if (data.errcode === 0) {
                    this.wallet = data.data
                }

            });
        },




        get_orderlist(){
            this.myaxios(this.baseurl + "wallet/", "post").then(data => {

                console.log(data);
                if (data.errcode === 0) {
                    this.orderlist = data.data
                }

            });
        }
            




        
      





          
    
},
  created() {
    this.get_wallet()
    this.get_orderlist()

    

  },
  mounted() {},
};
</script>


<style scoped>
@import url("../assets/style.css");
</style>

充值请求:

文件名是:pay.vue


<template>
  <div class="container">
    <a-layout>
      <a-layout-sider>
        <mymenu></mymenu>
      </a-layout-sider>
      <a-layout>

            <h2>充值页面</h2>
         
      </a-layout>
    </a-layout>
  </div>
</template>

<script>
// 导入子组件
import mymenu from "./mymenu.vue";
import { message } from "ant-design-vue";

import { createFromIconfontCN } from '@ant-design/icons-vue';

const IconFont = createFromIconfontCN({
    scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js',
});

export default {
  data() {
    return {
      
      collapsed: false,
      selectedKeys: ["1"],
      
      
      
    };
  },

  //声明组件
  components: {
    mymenu,
  },
  methods: {

            


            // 充值请求

            check_order(){
            this.myaxios(this.baseurl + "pay/", "post",{"out_trade_no":this.$route.query.out_trade_no,"trade_no":this.$route.query.trade_no,"total_amount":this.$route.query.total_amount,"timestamp":this.$route.query.timestamp}).then(data => {

                console.log(data);
                if (data.errcode === 0) {
                    this.$message.success(data.msg)
                    window.location.href="/wallet"
                }else{
                    this.$message.error(data.msg)
                    window.location.href="/wallet"
                }

            });
        }

          
    
},
  created() {

    this.check_order()

  },
  mounted() {},
};
</script>


<style scoped>
@import url("../assets/style.css");
</style>

第七步:

数据库内容,字段名

订单表:

 用户表:记得写钱包字段哦

 效果内容(show):

 点击支付宝充值:

 输入从沙箱获得的支付宝账号和密码。

点击确认付款!

后面还让输入支付密码!!!

钱包到账啦:

 

 这个就是支付宝支付,代码有效,修改即用!!!

 

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值