微信:支付

一  支付

https://www.cnblogs.com/xiaoyuanqujing/protected/articles/11822104.html

 

 

商户系统和微信支付系统主要交互:

1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API

2、商户server调用支付统一下单,api参见公共api【统一下单API

3、商户server调用再次签名,api参见公共api【再次签名

4、商户server接收支付通知,api参见公共api【支付结果通知API

下面的代码具体怎么用代码实现,我们再这里不讲,再后面文档中书写,我们先整理整体的业务逻辑

1小程序登入API解释

再之前的文档中我们已经对小程序的登入做了说明我们不在重复,如果有不懂的,可以参考前面的博客,如果不懂,可以再博客底下留言,我会第一时间回答

2统一下单接口解释

​ 1当用户发起下单请求,且用户是登入状态的情况下,我们就可以创建我们商城的订单了。

​ 2当订单创建完毕,我们应该发起支付,调用支付接口,也就是统一下单接口(这里的下单不是我们商城的下单,而是对微信官方进行支付下单),我们按照微信统一下单接口发送数据,微信下单接口会同步返回数据给我们,也就是上图中prepay_id

3再次签名

​ 1当我们拿到统一下的那数据以后,我们要再次进行签名(对数据加密以及处理)。

​ 2 然后将数据发送给我们小程序。

​ 3 小程序拿到我们发送的数据后调起支付界面,这样用户就可以进行支付了,如果支付成功,微信会直接返回 结果给我们小程序

4异步通知接口

​ 1在第三步再次签名中我们小程序已经知道用户是否支付成功,但是我们后端还不知道该订单是否支付成功

​ 2 基于1的问题,微信会以异步的方式通知我们后端程序,我们拿到微信异步通知的数据,我们就可以对订单 进行修改。那这样就实现了,前后都知道用户的支付结果。

示例:

1.前端

 

 

2.后端

2.1目录

 

 配置文件

1.settings.py
AppId="wx29fad388b1f51644"

AppSecret="d00c23ad3faf96ca218c20f6aaece7a7"

code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
#商户号
pay_mchid ='1415981402'

pay_apikey = 'xi34nu5jn7x2uujd8u4jiijd2u5d6j8e'

2.wx_login.py
from app01.wx import settings
import requests

def login(code):
    response=requests.get(settings.code2Session.format(settings.AppId,settings.AppSecret,code))
    data=response.json()
    if data.get("openid"):
        return data
    else:
        return False

3.wxbizdatacrypt.py
import base64
import json
from Crypto.Cipher import AES
from  app01.wx import settings

class WXBizDataCrypt:
    def __init__(self, appId, sessionKey):
        self.appId = appId
        self.sessionKey = sessionKey

    def decrypt(self, encryptedData, iv):
        # base64 decode
        sessionKey = base64.b64decode(self.sessionKey)
        encryptedData = base64.b64decode(encryptedData)
        iv = base64.b64decode(iv)

        cipher = AES.new(sessionKey, AES.MODE_CBC, iv)

        decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)))

        if decrypted['watermark']['appid'] != self.appId:
            raise Exception('Invalid Buffer')

        return decrypted

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]

    @classmethod
    def getInfo(cls,encryptedData,iv,session_key):

        return cls(settings.AppId,session_key).decrypt(encryptedData, iv)

cbv

from rest_framework.views import  APIView
from  rest_framework.response import  Response
from app01.wx import wx_login
from django.core.cache import cache
import hashlib,time
import random
from app01.wx import settings
import requests
class Pay(APIView):
    def post(self,request):
        param=request.data
        if param.get("login_key"):
            #缓存获取openid和session_key
            openid,session_key=cache.get(param.get("login_key")).split("&")
            self.openid=openid
            #如果是Nginx做的负载就要HTTP_X_FORWARDED_FOR
            if request.META.get('HTTP_X_FORWARDED_FOR'):
                self.ip =request.META['HTTP_X_FORWARDED_FOR']
            else:
                #如果没有用Nginx就用REMOTE_ADDR
                self.ip = request.META['REMOTE_ADDR']
            #调用自定义pay函数
            data = self.pay()
            return Response({"code":200,"msg":"ok","data":data})
        else:
            return Response({"code":200,"msg":"缺少参数"})

    #获取随机字符串函数(根据业务场景来)
    def get_str(self):
        str_all="1234567890abcdefghjklmasdwery"
        nonce_str="".join(random.sample(str_all,20))
        return nonce_str

    #获取订单号(根据实际场景来)
    def get_order(self):
        order_id=str(time.strftime("%Y%m%d%H%M%S"))
        return order_id

    #
    def xml_to_dict(self,data):
        import xml.etree.ElementTree as ET
        xml_dict={}
        data_dic=ET.fromstring(data)
        for item in data_dic:
            xml_dict[item.tag]=item.text
        return  xml_dict

   #签名
    def get_sign(self):
        data_dic = {
            "nonce_str": self.nonce_str,
            "out_trade_no": self.out_trade_no,
            "spbill_create_ip": self.ip,
            "notify_url": self.notify_url,
            "openid": self.openid,
            "body": self.body,
            "trade_type": "JSAPI",
            "appid": self.appid,
            "total_fee": self.total_fee,
            "mch_id": self.mch_id
        }
        sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
        sign_str = f"{sign_str}&key={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        return md5.hexdigest().upper()

    #支付函数
    def pay(self):
        self.appid=settings.AppId
        #商户号(封装文件中获取)
        self.mch_id=settings.pay_mchid
        #随机字符串(上面自定义函数获取)
        self.nonce_str=self.get_str()
        #商品描述(实际情况来)
        self.body="饼哥生活费"
        #订单号(自定义函数获取)
        self.out_trade_no=self.get_order()
        #支付金额
        self.total_fee=1
        #终端ip
        self.spbill_create_ip=self.ip
        #异步回调地址,根据实际情况来
        self.notify_url="http://www.baidu.com"
        #交易类型
        self.trade_type="JSAPI"
        #签名(自定义函数)
        self.sign = self.get_sign()
        #数据格式替换
        data=f'''
        <xml>
               <appid>{self.appid}</appid>
               <body>{ self.body}</body>
               <mch_id>{self.mch_id}</mch_id>
               <nonce_str>{self.nonce_str}</nonce_str>
               <notify_url>{self.notify_url}</notify_url>
               <openid>{self.openid}</openid>
               <out_trade_no>{self.out_trade_no}</out_trade_no>
               <spbill_create_ip>{self.spbill_create_ip}</spbill_create_ip>
               <total_fee>{self.total_fee}</total_fee>
               <trade_type>{self.trade_type}</trade_type>
               <sign>{self.sign}</sign>
        </xml>
        '''

        url="https://api.mch.weixin.qq.com/pay/unifiedorder"
        #向微信官方服务接口发送数据,response为xml格式数据
        response=requests.post(url,data.encode("utf-8"),headers={"content-type":"application/xml"})
        #调用自定义函数将xml格式数据转成字典
        res_data=self.xml_to_dict(response.content)
        #二次调用自定义签名
        data=self.two_sign(res_data["prepay_id"])
        return  data

    #二次签名函数
    def two_sign(self,prepay_id):
        timeStamp=str(int(time.time()))
        nonceStr=self.get_str()
        data_dict={
            "appId":settings.AppId,
            "timeStamp":timeStamp, #时间戳
            "nonceStr":nonceStr, #随机字符串
            "package":f"prepay_id={prepay_id}", #数据包
            "signType":"MD5" #签名类型
        }
        sign_str = "&".join([f"{k}={data_dict[k]}" for k in sorted(data_dict)])
        sign_str = f"{sign_str}&key={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign=md5.hexdigest().upper()
        data_dict["paySign"]=sign
        data_dict.pop("appId")

        return  data_dict



def get_access_token():
    accesston=requests.get()

 

posted @ 2020-03-29 00:39  心慌得初夏  阅读(261)  评论(0编辑  收藏  举报
levels of contents