0003 微信公众号开发

zengfanpei 2020-02-21

01 公众号接入

01.1 注册并登录微信公众平台。在公众平台首页最下面,找到开发/基本配置,记下开发者ID和开发者密码。

02.2 编写服务端程序

在WeChart APP下创建目录views_wechart,并创建文件constants.py文件:

# 微信的token令牌
WECHAT_TOKEN = "tongheng2"
# 开发者ID
WECHAT_APPID = "wxe2a552d82fd68c2a"
# 开发者密码
WECHAT_APPSECRET = "cbc983eddcf8b6223680abfbfd86933e"

# 微信服务器IP地址
SERVER_ID_ADDRESS = ‘111.229.48.106‘
# 缓存公众号access_token
WECHATPY_ACCESS_TOKEN_CACHE = ‘redis://:‘ + SERVER_ID_ADDRESS + ‘:6379/3‘
# 测试回调链接地址
REDIRECT_URI = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/wechatpyoauth/‘
# 注册页面
REGISTER_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/RegisterView/‘
# 管理员首页
ADMIN_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/AdminHomeView/‘
# 药师首页
YAOSHI_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/YaoshiHomeView/‘
# 用户首页
USER_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/UserHomeView/‘
# 医生首页
DOCTOR_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/DoctorHomeView/‘
# 医生助理首页
DOCTOR_ASSISTANT_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/DoctorAssistantHomeView/‘
# 财务首页
CAIWU_HOME_ADDRESS = ‘http://‘ + SERVER_ID_ADDRESS + ‘/ThirdParts/CaiwuHomeView/‘

02.3 在views_wechart目录下创建utils.py文件

import hashlib
from wechatpy.oauth import WeChatOAuth
from wechatpy.client import WeChatClient
from wechatpy.session.redisstorage import RedisStorage
from redis import Redis

from . import constants


def generate_signature(timestamp, nonce):
    """
    生成微信加密签名
    :param timestamp: 时间戳
    :param nonce: 随机数
    :return: signature
    """

    # 按照微信的流程进行计算签名
    sortlist = [constants.WECHAT_TOKEN, timestamp, nonce]
    # 排序
    # 1)将token、timestamp、nonce三个参数进行字典序排序
    sortlist.sort()

    # 拼接字符串
    tmp_str = "".join(sortlist)

    # 进行sha1加密, 得到正确的签名值
    # 2)将三个参数字符串拼接成一个字符串进行sha1加密
    # signature = hashlib.sha1(tmp_str).hexdigest()
    sha = hashlib.sha1()
    sha.update(tmp_str.encode(‘utf-8‘))
    signature = sha.hexdigest()

    return signature


def get_WeChatOAuth(redirect_uri, state=‘123‘, scope=‘snsapi_userinfo‘):
    """
    获取WeChatOAuth对象
    :param redirect_uri: 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
    :param scope:应用授权作用域,snsapi_base,snsapi_userinfo
    :param state:重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
    :return: WeChatOAuth对象
    """

    return WeChatOAuth(
        app_id=constants.WECHAT_APPID,
        secret=constants.WECHAT_APPSECRET,
        redirect_uri=redirect_uri,
        scope=scope,
        state=state
    )


def get_WeChatClient():
    """
    获取WeChatClient对象
    :return:WeChatClient对象
    """

    redis_client = Redis.from_url(constants.WECHATPY_ACCESS_TOKEN_CACHE)
    session_interface = RedisStorage(
        redis_client,
        prefix="wechatpy"
    )

    return WeChatClient(
        constants.WECHAT_APPID,
        constants.WECHAT_APPSECRET,
        session=session_interface
    )


def get_authorize_url(redirect_uri, state):
    """
    获取授权跳转地址
    :return: authorize_url
    """

    wechatOAuth = get_WeChatOAuth(redirect_uri, state)
    return wechatOAuth.authorize_url

02.4 在views_chart下创建文件Interface.py文件

from rest_framework import status
import logging
from django.http import HttpResponse
from wechatpy.utils import check_signature
from wechatpy.exceptions import InvalidSignatureException
from wechatpy.replies import TextReply
from wechatpy import parse_message
from django.views.generic import View

from . import constants
from .utils import get_authorize_url

# 获取在配置文件中定义的logger,用来记录日志
logger = logging.getLogger(‘tongheng‘)


class WeChatPy(View):
    """
    微信公众号开发服务器配置
    """

    # http://127.0.0.1:8000/ThirdParts/wechatpy/?signature=d8e259ac87cf08ea6924fbb78479bb1fcf53d4d6&echostr=1406649499520832760&timestamp=1581421688&nonce=929463593
    # GET /ThirdParts/wechatpy/?signature=d8e259ac87cf08ea6924fbb78479bb1fcf53d4d6&echostr=1406649499520832760&timestamp=1581421688&nonce=929463593
    @classmethod
    def get(cls, request):
        """
        微信服务器验证消息
        :param request:GET请求携带参数(signature、timestamp、nonce、echostr)
        :return:原样返回echostr参数
        """

        # logger.info("body:%s" % request.body)
        # logger.info("GET:%s" % request.GET)
        # logger.info("POST:%s" % request.POST)

        # 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        signature = request.GET.get(‘signature‘)
        # 时间戳
        timestamp = request.GET.get(‘timestamp‘)
        # 随机数
        nonce = request.GET.get(‘nonce‘)
        # 随机字符串
        echostr = request.GET.get(‘echostr‘)

        # logger.info("signature:%s" % signature)
        # logger.info("timestamp:%s" % timestamp)
        # logger.info("nonce:%s" % nonce)
        # logger.info("echostr:%s" % echostr)

        # 校验参数
        if not all([signature, timestamp, nonce, echostr]):
            # 请求参数错误
            return HttpResponse(status.HTTP_400_BAD_REQUEST)

        try:
            check_signature(constants.WECHAT_TOKEN, signature, timestamp, nonce)
        except InvalidSignatureException as e:
            # 处理异常情况或忽略
            logger.error(e)
            # 微信签名错误
            return HttpResponse(status.HTTP_403_FORBIDDEN)

        # 验证成功时,应原样返回 echostr 参数值
        return HttpResponse(echostr)

    # http://127.0.0.1:8000/ThirdParts/wechatpy/
    # POST /ThirdParts/wechatpy/
    @classmethod
    def post(cls, request):
        """
        当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
        """

        # logger.info("body:%s" % request.body)
        # logger.info("GET:%s" % request.GET)
        # logger.info("POST:%s" % request.POST)

        # 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        signature = request.GET.get(‘signature‘)
        # 时间戳
        timestamp = request.GET.get(‘timestamp‘)
        # 随机数
        nonce = request.GET.get(‘nonce‘)
        # openid
        openid = request.GET.get(‘openid‘)

        # logger.info("signature:%s" % signature)
        # logger.info("timestamp:%s" % timestamp)
        # logger.info("nonce:%s" % nonce)
        # openid:o-dlPwDD8x_tKgeinvgj9CY9sfSI
        # logger.info("openid:%s" % openid)

        # 校验参数
        if not all([signature, timestamp, nonce, openid]):
            # 请求参数错误
            return HttpResponse(status.HTTP_400_BAD_REQUEST)

        try:
            check_signature(constants.WECHAT_TOKEN, signature, timestamp, nonce)
        except InvalidSignatureException as e:
            # 处理异常情况或忽略
            logger.error(e)
            # 微信签名错误
            return HttpResponse(status.HTTP_403_FORBIDDEN)

        xml = request.body
        logger.info("xml:%s" % xml)
        if not xml:
            # 请求参数错误
            return HttpResponse(status.HTTP_400_BAD_REQUEST)

        msg = parse_message(xml)
        msg_type = msg.type
        # logger.info("msg type:%s" % type(msg))
        # logger.info("msg_type:%s" % msg_type)

        msg_content = None
        if msg_type == "event":
            # 推送事件
            if msg.event == "subscribe":
                # 关注公众号
                authorize_url = get_authorize_url(constants.REGISTER_HOME_ADDRESS, ‘subscribe‘)
                msg_content = ‘感谢你关注,请点击<a href="‘ + authorize_url + ‘">注册</a>‘
        elif msg_type == "text":
            # 文本消息
            if msg.content == "注册":
                authorize_url = get_authorize_url(constants.REGISTER_HOME_ADDRESS, ‘register‘)
                msg_content = ‘请点击<a href="‘ + authorize_url + ‘">注册</a>‘

        if msg_content is not None:
            reply = TextReply(content=msg_content, message=msg)
            # 转换成 XML
            xml = reply.render()
            return HttpResponse(xml)
        else:
            return HttpResponse(‘‘)

相关推荐