欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

前后端分离djangorestframework—— 接入微信模板消息推送

程序员文章站 2024-03-31 08:20:46
微信 什么是微信也不多说,跟前面的支付宝一样的 微信支付 微信支付也有个沙箱环境,沙箱环境官方文档 由文档中那句很显眼的话所得,即使是测试环境也需要真实的商户号,所以这个就没法想支付宝那样用沙箱账号来演示了。至于为什么没有沙箱账号这就不得而知了,想接入微信支付商户的朋友,请移步先注... ......

微信

什么是微信也不多说,跟前面的支付宝一样的

微信支付

微信支付也有个沙箱环境,  

前后端分离djangorestframework—— 接入微信模板消息推送

 

由文档中那句很显眼的话所得,即使是测试环境也需要真实的商户号,所以这个就没法想支付宝那样用沙箱账号来演示了。至于为什么没有沙箱账号这就不得而知了,想接入微信支付商户的朋友,请移步先注册为商户,上传相关资料审核后方可使用:传送门 

 

所以关于微信支付,由于这些种种限制,就不去注册商户了,所以支付方面本文在此略过,感兴趣的朋友自己去研究了,我看微信的文档也很浅显易懂的 

 

微信模板消息推送

 

因为微信的模板消息推送改版,现在需要认证的微信企业号才能玩,所以目前来说我们只能使用微信给的沙箱测试平台了, 

用你的微信登录,之后会给我们自动生成一个id 和key:

前后端分离djangorestframework—— 接入微信模板消息推送

还有一个测试的可用公众账号:

前后端分离djangorestframework—— 接入微信模板消息推送

 

接着按微信官方给的文档:

 

其实大概的流程就是这样:

 

 

前后端分离djangorestframework—— 接入微信模板消息推送

 

 

1.默认情况下,用户的微信只和微信服务端有联系,且微信服务端里有用户的唯一id,而我们的平台的目标是要通过公众号给用户发消息

2.但是默认用户的微信和我们平台的微信不相通的,如隔了一道墙

3.我们给用户一个页面,页面上有我们的二维码,让用户扫码关注我们的公众号

4.在第3步操作也是通过微信的服务端作为中间人完成的,且当用户关注成功的同时,微信服务端会把用户id自动回传(或者说回调)给我们平台的公众号

5.拿到用户id之后,我们的微信公众号就可以给用户推送消息了

 

其实步骤是挺简单的,上面5步中,其实实际的业务逻辑只有第3,第4和第5三个步骤,且这几个步骤里每个的请求url都需要通过微信服务端来完成,所以还需要再看下微信的官方文档给我们解说的

 

 

前期准备:

 

1,修改地址:

还是刚才那个申请测试账号页面,滑动下面,找到网页账号这里,点修改

前后端分离djangorestframework—— 接入微信模板消息推送

 

看到的提示,写得很清楚,我这里只是作为测试而已,这个地址不能是127.0.0.1换回地址了,至少得是局域网地址,因为一会儿用手机微信测试时需要调用这个地址,所以你的手机得和电脑是同一个局域网段,当然真实的使用时是公网的地址

 前后端分离djangorestframework—— 接入微信模板消息推送

 

 

 

 点击确认之后,显示通过安全检测的话就配置成功了

前后端分离djangorestframework—— 接入微信模板消息推送

 

 

2.还要创建一个模板,获取一个模板id

点新增测试模板:添加模板时注意格式

前后端分离djangorestframework—— 接入微信模板消息推送

 

按照文档给的提示操作就行,提交之后如下,所以你如果填错了,只能删除重新添加,不能修改

前后端分离djangorestframework—— 接入微信模板消息推送

 

 

3.作为接收信息的用户微信号必须关注测试账号:

前后端分离djangorestframework—— 接入微信模板消息推送

 4.如果有需要的话,设置js的sdk url

当然是要调用微信的sdk时才会用到这个

前后端分离djangorestframework—— 接入微信模板消息推送

 

代码实现

 

前面的准备工作准备好之后,开始写代码 

 

不过,先通过微信的文档,得知我们此时需要用的url:

 

1.https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=redirect_uri&response_type=code&scope=scope&state=state#wechat_redirect

 

相关参数:

参数

必须

说明

appid

公众号的唯一标识(这个就是我们前面申请的)

redirect_uri

授权后重定向的回调链接地址(我们前面申请的)

response_type

返回类型,请填写code

scope

应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)

state

重定向后会带上state参数,开发者可以填写a-za-z0-9的参数值,最多128字节,该值会被微信原样返回,我们可以将其进行比对,防止别人的攻击。

#wechat_redirect

直接在微信打开链接,可以不填此参数。做页面302重定向时候,必须带此参数

 

 

 

 2.获取token的url:https://api.weixin.qq.com/sns/oauth2/access_token

相关参数:

appid

您的测试id号

secret

您的测试id的secret

code

微信自动回传的参数,用request.get.get("code")获取

grant_type

authorization_code

 

 

3.发送模板消息的接口:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=access_token

 

 前后端分离djangorestframework—— 接入微信模板消息推送

 前后端分离djangorestframework—— 接入微信模板消息推送

4.发送非模板正文信息的url:https://api.weixin.qq.com/cgi-bin/message/custom/send

 

 

好的,开始码代码,干!

 

创建一个名为wachattest的django项目,app名就是app:

前后端分离djangorestframework—— 接入微信模板消息推送

 

 然后因为要生成二维码,此处运用了qrcode.js的第三方js库   文件下载:

 

根目录创建static目录,存放如下文件,wx.jpg就是刚才那个测试微信公众号的图片,我把它下载下来并更名为wx.jpg了

前后端分离djangorestframework—— 接入微信模板消息推送

 

 

url:

 前后端分离djangorestframework—— 接入微信模板消息推送

html:

前后端分离djangorestframework—— 接入微信模板消息推送

settings:

前后端分离djangorestframework—— 接入微信模板消息推送

 还是配置文件部分,如果你启动项目时提示allow_hosts之类的错误,作如下更改:

前后端分离djangorestframework—— 接入微信模板消息推送

views:

前后端分离djangorestframework—— 接入微信模板消息推送

前后端分离djangorestframework—— 接入微信模板消息推送

前后端分离djangorestframework—— 接入微信模板消息推送

前后端分离djangorestframework—— 接入微信模板消息推送

与模板相关的配置,注意与之前创建的模板对应

前后端分离djangorestframework—— 接入微信模板消息推送

前后端分离djangorestframework—— 接入微信模板消息推送

前后端分离djangorestframework—— 接入微信模板消息推送

model,db_index=true的意思是自动在数据创建素银的意思

前后端分离djangorestframework—— 接入微信模板消息推送

 

运行项目之前记得迁移数据库,并写入几个数据作为测试

 

启动项目,登录再关注,不多说

前后端分离djangorestframework—— 接入微信模板消息推送

 

 登录成功之后,绑定页面,点击按钮之后,把这个测试的公众号二维码图片转成了带有一些参数的url,然后qrcode把这个带有参数的url转成了二维码:

 

前后端分离djangorestframework—— 接入微信模板消息推送

我用一个微信号测试扫码之后(前提必须先关注那个微信公众测试号才能授权),点击允许

 

前后端分离djangorestframework—— 接入微信模板消息推送

 

然后会跳转到这个界面,表示成功授权

 

前后端分离djangorestframework—— 接入微信模板消息推送

 

现在再做最终的模板消息发送,访问/sendmsg:

前后端分离djangorestframework—— 接入微信模板消息推送

 

 

查看手机端信息,得到的信息正好是我们之前设置的

 前后端分离djangorestframework—— 接入微信模板消息推送

 

大概的流程就走完了,因为我只是测试,没有做得多么高大上,其实比如那个模板消息,可以根据不同的用户发不同的数据,或者这段数据直接搞一个form表单,让非开发人员也可以使用它,点击发送就行了,还有上面说的那个当前用户的问题,只给当前用户发,不给没有操作的人发,或者定向群发啥啥的,反正主要的开发逻辑就这些,其他的随便玩,玩出花来都可以

 

 

微信官方的全部流程:传送门

 

相关的代码:

前后端分离djangorestframework—— 接入微信模板消息推送
import hashlib
from django.db import models


class 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)
models
前后端分离djangorestframework—— 接入微信模板消息推送
from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('bind/', views.bind),
    path('bind_qrcode/', views.bindqrcode),
    path('callback/', views.callback),
    path('sendmsg/', views.sendmsg)
]
urls
前后端分离djangorestframework—— 接入微信模板消息推送
from django.shortcuts import render, httpresponse, redirect
from django.http import jsonresponse
from django.conf import settings
import requests
from app import models
import json


# create your views here.
def 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')


def bind(request):
    """用户绑定页面"""
    return render(request, 'auth.html')


def bindqrcode(request):
    """生成二维码"""
    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=settings.wechat_config["app_id"],
            redirect_uri=settings.wechat_config["redirect_uri"],
            state=request.session['user_info']['uid']
        )
        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")

    # 用户uid
    state = request.get.get("state")

    # 获取该用户openid(用户唯一,用于给用户发送消息)
    res = requests.get(
        url="https://api.weixin.qq.com/sns/oauth2/access_token",
        params={
            "appid": settings.wechat_config["app_id"],
            "secret": settings.wechat_config["appsecret"],
            "code": code,
            "grant_type": 'authorization_code',
        }
    ).json()
    # 获取的到openid表示用户授权成功

    openid = res.get("openid")
    if openid:
        models.userinfo.objects.filter(uid=state).update(wx_id=openid)
        response = "<h1>授权成功 %s </h1>" % openid
    else:
        response = "<h1>用户扫码之后,手机上的提示</h1>"
    return httpresponse(response)


def get_access_token():
    """获取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


def send_content_msg(user_id, access_token):
    """内容消息发送"""
    body = {
        'touser': user_id,
        'msgtype': 'text',
        'text': {
            'content': '内容。。。。。不是模板消息'
        }
    }
    response = requests.post(
        url='https://api.weixin.qq.com/cgi-bin/message/custom/send',
        params={
            'access_token': access_token
        },
        data=bytes(json.dumps(body, ensure_ascii=false), encoding='utf-8')
    )
    result = response.json()
    return result


def send_template_msg(user_id, access_token):
    """模板消息发送"""
    result = requests.post(
        url='https://api.weixin.qq.com/cgi-bin/message/template/send',
        params={
            'access_token': access_token
        },
        json={
            "touser": user_id,
            "template_id": settings.wechat_config['template_id'],
            "data": {
                "first": {
                    "value": "微信模板页面发送消息",
                    "color": "#173177"
                },
                "kw1": {
                    "value": "卧槽调这个参数搞了有点久",
                    "color":"#173177"
                },
                "kw2": {
                    "value": "可不是咋地"
                },
                "kw3": {
                    "value": "就看这次能不能成功了"
                },
            }
        }
    )
    result = result.json()
    return result


def sendmsg(requet):
    access_token = get_access_token()
    # 这里由于我本来就只有一个数据,所以直接写死了,真实的开发当然是用当前登录用户扫码关注的用户对应
    userobj = models.userinfo.objects.filter(id=1).first()
    # 发送模板消息
    result = send_template_msg(userobj.wx_id, access_token)

    # 发送正文消息
    # result = send_content_msg(userobj.wx_id, access_token)

    if result.get('errcode') == 0:
        return httpresponse('发送成功')
    return httpresponse('发送失败')
views
前后端分离djangorestframework—— 接入微信模板消息推送
{% load staticfiles %}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>用户授权</title>
    <script src="{% static "js/jquery.min.js" %}"></script>
    <script src="{% static "js/jquery.qrcode.min.js" %}"></script>
    <script src="{% static "js/qrcode.js" %}"></script>
</head>
<body>
<input onclick="userauth() " type="button" value="关注我们有惊喜哦">
<div>
    <img style="height: 100px;width: 100px" src="{% static 'img/wx.jpg' %}">
</div>
<div id="qrcode" style="width: 250px;height: 250px;background-color: white;margin: 100px auto;"></div>
<script type="text/javascript">
    function userauth() {
        $.ajax({
            url: '/bind_qrcode/',
            type: 'get',
            success: function (data) {
                console.log(data);
                $('#qrcode').empty().qrcode({text: data.data});
            }
        });
    }
</script>
</body>
</html>
html:auth.html
前后端分离djangorestframework—— 接入微信模板消息推送
allowed_hosts = ['192.168.0.8']


static_url = '/static/'
staticfiles_dirs = (
    os.path.join(base_dir, 'static'),
)

# ############# 微信 ##############
wechat_config = {
    'app_id': '您的微信app测试id',  # 微信给的测试app id
    'appsecret': '您的微信app测试secret',  # 微信给的测试app sercret
    'redirect_uri': 'http://您的域名地址/callback/',  # 用户关注之后微信回传地址
    'template_id': "您的微信测试模板id"  # 模板id
}
settings主要的改动部分
前后端分离djangorestframework—— 接入微信模板消息推送
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>title</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user" placeholder="用户名">
        <input type="password" name="pwd" placeholder="密码">
        <input type="submit" value="登录">
    </form>
</body>
</html>
html:login.html

 

 

总结:

感觉还是挺简单的,就是对于刚接触的朋友来说的话,可能不习惯去看第三方的api文档,也不知道怎么下手,多研究就行了,熟练了就很快了

微信支付那个,我没有企业相关材料,而且就算有,也不敢那么随意的就为了做个测试就去申请什么的,所以相关的还是看官方文档吧