博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
$Django 支付宝支付,微信服务号推送消息 (测试需要把应用程序部署到服务器上)...
阅读量:5082 次
发布时间:2019-06-13

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

一 支付宝支付

  大概

支付宝支付        正式环境:需要用营业执照去申请商户号,appid        测试环境:沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info                 支付宝提供接口:给商户使用,收钱        -Java,php,C#的demo,没有python的demo(事例)                -git有人封装了        -需要安装模块:pip3 install pycryptodome        -应用私钥---自己保存,一定不能丢        -应用公钥---给别人用        -支付宝公钥---支付宝用的        -生成公钥私钥:https://docs.open.alipay.com/291/105971        -把应用公钥配置在支付宝上:应用公钥,配置完成以后,支付宝自动生成一个支付宝公钥                -在程序中:配置应用私钥,支付宝公钥                -如果支付成功,支付宝会回调,但是如果你的服务器挂掉了怎么办?            -支付宝24小时以内不定时再给你发,你修改掉订单状态即可        -支付成功,支付宝会有一个get回调,一个post回调:修改订单状态

  沙箱测试流程(详情)

   1.输入支付金额:在我们的网站往支付宝的网关https://openapi.alipaydev.com/gateway.do后面拼?账单(商品名,价格,我数据库生成的订单号等),回调的url等数据  

   2.扫码支付:点击去支付来到了拼好的支付宝url 显示支付宝页面

 

  3.支付完成:

  4.回调之前拼接的url:支付宝向这个url 发起get请求:GET取数据【显示】支付成功失败和post请求:body(bytes格式)内取数据:状态/我数据库的订单号/支付宝的订单号等

    

  代码(详情)

  1.目录

  

  2.keys:应用私钥,支付宝公钥

alipay_public_2048.txt      -----BEGIN PUBLIC KEY-----  # 加上这行          支付宝的公钥      -----END PUBLIC KEY-----   # 同上    app_private_2048.txt      -----BEGIN PUBLIC KEY-----  #同上          应用的私钥      -----END PUBLIC KEY-----   # 同上

  3.pay.py:这是从git上找到的支付宝支付接口(PC端支付接口) 

from datetime import datetimefrom Crypto.PublicKey import RSAfrom Crypto.Signature import PKCS1_v1_5from Crypto.Hash import SHA256from urllib.parse import quote_plusfrom 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)
支付宝接口

  4.路由

from django.contrib import adminfrom django.conf.urls import urlfrom app01 import viewsurlpatterns = [    url('admin/', admin.site.urls),    url(r'^page1/', views.page1),    url(r'^page2/', views.page2),]

  5.views

from django.shortcuts import render, redirect, HttpResponsefrom utils.pay import AliPayimport jsonimport timedef ali():    # 沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info    app_id = "2016092000554611"    # 支付宝收到用户的支付,会向商户发两个请求,一个get请求,一个post请求    # POST请求,用于最后的检测    notify_url = "http://42.56.89.12:80/page2/"    # GET请求,用于页面的跳转展示    return_url = "http://42.56.89.12:80/page2/"    #应用私钥    merchant_private_key_path = "keys/app_private_2048.txt"    #支付宝公钥    alipay_public_key_path = "keys/alipay_public_2048.txt"    # 生成一个AliPay的对象    alipay = AliPay(        appid=app_id,        app_notify_url=notify_url,        return_url=return_url,        app_private_key_path=merchant_private_key_path,        alipay_public_key_path=alipay_public_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥        debug=True,  # 默认False,    )    return alipaydef page1(request):    if request.method == "GET":        return render(request, 'page1.html')    else:        money = float(request.POST.get('money'))        # 生成一个对象        alipay = ali()        # 生成支付的url        # 对象调用direct_pay        query_params = alipay.direct_pay(            subject="充气娃娃",  # 商品简单描述            out_trade_no="x2" + str(time.time()),  # 商户订单号            total_amount=money,  # 交易金额(单位: 元 保留俩位小数)        )        pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params)        print(pay_url)        # 朝这个地址发get请求        return redirect(pay_url)def page2(request):    alipay = ali()    if request.method == "POST":        # 检测是否支付成功        # 去请求体中获取所有返回的数据:状态/订单号        from urllib.parse import parse_qs        body_str = request.body.decode('utf-8')        print(body_str)        post_data = parse_qs(body_str)        print('支付宝给我的数据:::---------',post_data)        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)        print('POST验证', status)        return HttpResponse('POST返回')    else:        params = request.GET.dict()        sign = params.pop('sign', None)        status = alipay.verify(params, sign)        print('GET验证', status)        return HttpResponse('支付成功')

  6.template

    
Title
{
% csrf_token %}

 

二 微信服务号推送消息

  大概

用什么推送        -邮件        -微信推送        -短信推送    微信推送        -公众号(群聊)            -认证的公众号:需要营业执照,需要交钱,可以发多篇文章            -未认证的公众号:一天只能发一篇文章        -服务号(微信推送)(私聊)            -需要申请,需要认证            -可以主动给单个用户推送消息            -能给推送的人,必须关注我的服务号            -沙箱环境:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
-企业号 -企业里用的: -你们所见的二维码:其实就是一个url地址 -咱们在前端通过url(https://open.weixin.qq.com/connect/oauth2.....)生成一个二维码 -注意*****修改:网页授权获取用户基本信息

  代码(详情)

  1.目录

  

  2.路由

from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [    url(r'^admin/', admin.site.urls),    url(r'^login/$', views.login),    url(r'^index/$', views.index),    url(r'^bind/$', views.bind),    url(r'^bind_qcode/$', views.bind_qcode),    url(r'^callback/$', views.callback),    url(r'^sendmsg/$', views.sendmsg),]

  3.settings.py

# ############# 微信 ##############WECHAT_CONFIG = {    'app_id': 'wx3e1f0883236623f9',    'appsecret': '508ec4590702c76e6863be6df01ad95a',    'redirect_uri': 'http://42.56.89.12/callback/',}

  4.models.py

import hashlibfrom django.db import modelsclass UserInfo(models.Model):    username = models.CharField("用户名", max_length=64, unique=True)    password = models.CharField("密码", max_length=64)    uid = models.CharField(verbose_name='个人唯一ID',max_length=64, unique=True)    wx_id = models.CharField(verbose_name="微信ID", max_length=128, blank=True, null=True, db_index=True)    def save(self, *args, **kwargs):        # 创建用户时,为用户自动生成个人唯一ID        if not self.pk:            m = hashlib.md5()            m.update(self.username.encode(encoding="utf-8"))            self.uid = m.hexdigest()        super(UserInfo, self).save(*args, **kwargs)

  5.views.py

import jsonimport functoolsimport requestsfrom django.conf import settingsfrom django.shortcuts import render, redirect, HttpResponsefrom django.http import JsonResponsefrom app01 import models# 沙箱环境地质:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/logindef index(request):    obj = models.UserInfo.objects.get(id=1)    return render(request,'index.html',{
'obj':obj})def auth(func): def inner(request, *args, **kwargs): user_info = request.session.get('user_info') if not user_info: return redirect('/login/') return func(request, *args, **kwargs) return innerdef login(request): """ 用户登录 :param request: :return: """ # models.UserInfo.objects.create(username='luffy',password=123) if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') obj = models.UserInfo.objects.filter(username=user, password=pwd).first() if obj: request.session['user_info'] = {
'id': obj.id, 'name': obj.username, 'uid': obj.uid} return redirect('/bind/') else: return render(request, 'login.html')@authdef bind(request): """ 用户登录后,关注公众号,并绑定个人微信(用于以后消息推送) :param request: :return: """ return render(request, 'bind.html')@authdef bind_qcode(request): """ 生成二维码 :param request: :return: """ ret = {
'code': 1000} try: access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect" access_url = access_url.format( # 商户的appid appid=settings.WECHAT_CONFIG["app_id"], # 'wx6edde7a6a97e4fcd', # 回调地址 redirect_uri=settings.WECHAT_CONFIG["redirect_uri"], # 当前登录用户的唯一id state=request.session['user_info']['uid'] # 为当前用户生成MD5值 ) ret['data'] = access_url except Exception as e: ret['code'] = 1001 ret['msg'] = str(e) return JsonResponse(ret)def callback(request): """ 用户在手机微信上扫码后,微信自动调用该方法。 用于获取扫码用户的唯一ID,以后用于给他推送消息。 :param request: :return: """ code = request.GET.get("code") # 用户md5值,用户唯一id state = request.GET.get("state") # 获取该用户openId(用户唯一,用于给用户发送消息) # request模块朝https://api.weixin.qq.com/sns/oauth2/access_token地址发get请求 res = requests.get( url="https://api.weixin.qq.com/sns/oauth2/access_token", params={ "appid": 'wx3e1f0883236623f9', "secret": '508ec4590702c76e6863be6df01ad95a', "code": code, "grant_type": 'authorization_code', } ).json() # res.data 是json格式 # res=json.loads(res.data) # res是一个字典 # 获取的到openid表示用户授权成功 openid = res.get("openid") if openid: models.UserInfo.objects.filter(uid=state).update(wx_id=openid) response = "

授权成功 %s

" % openid else: response = "

用户扫码之后,手机上的提示

" return HttpResponse(response)def sendmsg(request): def get_access_token(): """ 获取微信全局接口的凭证(默认有效期俩个小时) 如果不每天请求次数过多, 通过设置缓存即可 """ result = requests.get( url="https://api.weixin.qq.com/cgi-bin/token", params={ "grant_type": "client_credential", "appid": settings.WECHAT_CONFIG['app_id'], "secret": settings.WECHAT_CONFIG['appsecret'], } ).json() if result.get("access_token"): access_token = result.get('access_token') else: access_token = None return access_token access_token = get_access_token() openid = models.UserInfo.objects.get(id=1).wx_id def send_custom_msg(): body = { "touser": openid, "msgtype": "text", "text": { "content": 'lqz大帅哥' } } response = requests.post( url="https://api.weixin.qq.com/cgi-bin/message/custom/send", # 放到路径?后面的东西 params={ 'access_token': access_token }, # 这是post请求body体中的内容 data=bytes(json.dumps(body, ensure_ascii=False), encoding='utf-8') ) # 这里可根据回执code进行判定是否发送成功(也可以根据code根据错误信息) result = response.json() return result def send_template_msg(): """ 发送模版消息 """ res = requests.post( url="https://api.weixin.qq.com/cgi-bin/message/template/send", params={ 'access_token': access_token }, json={ "touser": openid, "template_id": 'IaSe9s0rukUfKy4ZCbP4p7Hqbgp1L4hG6_EGobO2gMg', "data": { "first": { "value": "lqz", "color": "#173177" }, "keyword1": { "value": "大帅哥", "color": "#173177" }, } } ) result = res.json() return result result = send_custom_msg() if result.get('errcode') == 0: return HttpResponse('发送成功') return HttpResponse('发送失败')
视图

  6.template.py

    
Title
{
% csrf_token %}
login.html
{% load staticfiles %}    
Title

请关注路飞学城服务号,并绑定个人用户(用于以后的消息提醒)

第一步:关注路飞学城微信服务号

第二步:绑定个人账户

{
#qrcode 可以生成二维码 #}
bind.html(重点)
    
Title

{
{ obj.username }} -> {
{ obj.wx_id }}

index.html

  沙箱测试流程(详情)

  1.先去微信 https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login申请服务号:拿到appid,appsecret,服务号二维码

 

 

   2.为了给微信用户推送信息(我们的服务器数据库要存上用户的微信号,如上图):先要关注服务号,然后诱导用户向我们拼好的一个微信url连接发请求

ret = {
'code': 1000} try: access_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_userinfo&state={state}#wechat_redirect" access_url = access_url.format( # 商户的appid appid=settings.WECHAT_CONFIG["app_id"], # 'wx6edde7a6a97e4fcd', # 回调地址 redirect_uri=settings.WECHAT_CONFIG["redirect_uri"], # 当前登录用户的唯一id state=request.session['user_info']['uid'] # 为当前用户生成MD5值 ) ret['data'] = access_url except Exception as e: ret['code'] = 1001 ret['msg'] = str(e)
拼好的链接(回调地址,我们服务器用户信息,appid,appsecret,)
{#qrcode 可以生成二维码 #}
url生成二维码,让用户扫

  3.回调地址:微信根据回调地址再向我们服务器发请求,获得数据的同时我们服务器又向微信某个地址发送了一个request.get(爬虫请求)直接拿到了用户的微信号,更新到我们的数据库

#回调地址的路由url(r'^callback/$', views.callback)def callback(request):    """    用户在手机微信上扫码后,微信自动调用该方法。    用于获取扫码用户的唯一ID,以后用于给他推送消息。    :param request:     :return:     """    code = request.GET.get("code")    # 用户md5值,用户唯一id    state = request.GET.get("state")    # 获取该用户openId(用户唯一,用于给用户发送消息)    # request模块朝https://api.weixin.qq.com/sns/oauth2/access_token地址发get请求    res = requests.get(        url="https://api.weixin.qq.com/sns/oauth2/access_token",        params={            "appid": 'wx3e1f0883236623f9',            "secret": '508ec4590702c76e6863be6df01ad95a',            "code": code,            "grant_type": 'authorization_code',        }    ).json()    # res.data   是json格式    # res=json.loads(res.data)    # res是一个字典    # 获取的到openid表示用户授权成功    openid = res.get("openid")    if openid:        models.UserInfo.objects.filter(uid=state).update(wx_id=openid)        response = "

授权成功 %s

" % openid else: response = "

用户扫码之后,手机上的提示

" return HttpResponse(response)

  4.最终:用户扫码后会得到回调地址的返回信息,例如 '授权成功'

  5.我们定义了一个sendmsg(request)视图:1爬取当前用户的token,2服务器拿着token、用户微信号向微信发消息。这样用户就收到了服务号私发的信息

def sendmsg(request):    def get_access_token():        """        获取微信全局接口的凭证(默认有效期俩个小时)        如果不每天请求次数过多, 通过设置缓存即可        """        result = requests.get(            url="https://api.weixin.qq.com/cgi-bin/token",            params={                "grant_type": "client_credential",                "appid": settings.WECHAT_CONFIG['app_id'],                "secret": settings.WECHAT_CONFIG['appsecret'],            }        ).json()        if result.get("access_token"):            access_token = result.get('access_token')        else:            access_token = None        return access_token    access_token = get_access_token()    openid = models.UserInfo.objects.get(id=1).wx_id    def send_custom_msg():        body = {            "touser": openid,            "msgtype": "text",            "text": {                "content": 'lqz大帅哥'            }        }        response = requests.post(            url="https://api.weixin.qq.com/cgi-bin/message/custom/send",            # 放到路径?后面的东西            params={                'access_token': access_token            },            # 这是post请求body体中的内容            data=bytes(json.dumps(body, ensure_ascii=False), encoding='utf-8')        )        # 这里可根据回执code进行判定是否发送成功(也可以根据code根据错误信息)        result = response.json()        return result    def send_template_msg():        """        发送模版消息        """        res = requests.post(            url="https://api.weixin.qq.com/cgi-bin/message/template/send",            params={                'access_token': access_token            },            json={                "touser": openid,                "template_id": 'IaSe9s0rukUfKy4ZCbP4p7Hqbgp1L4hG6_EGobO2gMg',                "data": {                    "first": {                        "value": "lqz",                        "color": "#173177"                    },                    "keyword1": {                        "value": "大帅哥",                        "color": "#173177"                    },                }            }        )        result = res.json()        return result    result = send_custom_msg()    if result.get('errcode') == 0:        return HttpResponse('发送成功')    return HttpResponse('发送失败')
服务号向粉丝发消息

 

 

  

 

 

 

转载于:https://www.cnblogs.com/3sss-ss-s/p/10185255.html

你可能感兴趣的文章
Java int 与 Integer 区别
查看>>
Cenots7下安装运行.NET Core、MicroSoft SQL Server 2019 preview 的基础实践
查看>>
第二阶段个人冲刺05
查看>>
coffee 编译时, 用本地环境
查看>>
jzoj 6271. 2019.8.4【NOIP提高组A】锻造 (forging)
查看>>
Java面向对象和特征
查看>>
【算法与数据结构实战】线性表操作-实现A并B,结果放入A中
查看>>
20141225 数组二
查看>>
发布-订阅消息系统Kafka简介
查看>>
六、面向切面的spring(2)
查看>>
字符串匹配算法之BM算法
查看>>
比特币中的Base58 编码
查看>>
并发编程(三)
查看>>
linq.js
查看>>
线段树||BZOJ5194: [Usaco2018 Feb]Snow Boots||Luogu P4269 [USACO18FEB]Snow Boots G
查看>>
(转)得到系统服务号的硬编码
查看>>
React Native 增量升级方案(转)
查看>>
深入理解TCP(一)
查看>>
JavaEE笔记(八)
查看>>
easyui +springMVC+MyBatis datagrid分页
查看>>