【小程序】基于.NET CORE2.1 的 微信开放平台 第三方平台开发 教程一 准备工做

微信第三方平台概述

公众平台第三方平台是为了让公众号或小程序运营者,在面向垂直行业需求时,能够一键受权给第三方平台(而且能够同时受权给多家第三方),经过第三方平台来完成业务,开放给全部经过开发者资质认证后的开发者使用。sql

详细说明请访问 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318292&lang=数据库

这里啰嗦一下,什么是微信第三方平台,有什么做用?

官方介绍:微信第三方平台的开放,是为了让公众号或小程序运营者,在面向垂直行业需求时,能够一键登陆受权给第三方的公众号或小程序运营平台,经过第三方开发者提供的公众号或小程序第三方平台来完成相关业务。json

从技术上简单来讲,客户无需提供技术人员对接。无需了解微信后台开发者相关配置,好比配置Appid,AppSecret,URL,Token等等不少东西,客户只须要经过扫一扫受权给第三方平台就能获得第三方平台微信受权的相关运营功能。前提是第三方平台已经彻底对接微信开放平台的大部分功能。小程序

这一篇主要是讲解如何经过.NET CORE2.1技术开发后台对接微信开放平台的小程序受权。微信小程序

废话很少说,你们都知道磨刀不误砍柴工,因此建议你们都去看一遍微信开放平台文档,文档说明已经很详细了。至少本身心中要有大概的了解及思路。地址 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318292&token=&lang=服务器

开发必备工具

IDE:VS2017微信

运行环境:netcoreapp2.1app

数据库:Mysql框架

框架主要运用技术及组件:

  • .NET Core 2.1
  • Entity Framework Core 2.1.0
  • Pomelo.EntityFrameworkCore.MySql 2.1.0-rc1-final
  • Senparc.Weixin.Open 2.10.5

微信开放平台准备

一、注册微信开放平台帐户,并经过企业认证。dom

二、进入管理中心,切换到【第三方平台】建立第一个第三方平台

第三方平台可开通微信公众号受权、小程序受权,根据贵公司的开放进度及功能开放程度进行选择。

具体步骤

在第三方平台方建立成功并最终开发测试完毕,提交全网发布申请时,微信服务器会经过自动化测试的方式,检测服务的基础逻辑是否可用,在确保基础可用的状况下,才会容许公众号或小程序第三方平台提交全网发布。

微信后台会自动将下述公众号配置为第三方平台方的一个额外的测试公众号,并经过该账号,执行以下所述的测试步骤,第三方平台方须要根据各步骤描述的自动化测试规则实现相关逻辑,才能经过接入检测,达到全网发布的前提条件。

请注意,必须预先按照测试各步骤要求,代码实现相关逻辑后,去点击“全网发布”按钮,才有可能全网发布成功。

三、以小程序受权Demo来介绍相关参数

 

开发参数配置 相关参数说明 访问 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318462&lang=zh_CN

白名单IP配置容许用户在全网未发布状态下用于在线环境开发测试。

小程序模板配置

 

以上就是第三方平台的基础配置信息。

4.基于.NET CORE 2.1搭建一个简单的第三方平台。

新建一个空的解决方案。主要用于第三方受权及小程序业务管理。

 

第三方平台与微信开放平台的业务对接咱们直接使用 Senparc的Open组件

 

安装组件完成以后,咱们须要作的是要获取微信开放平台主动推送的 component_verify_ticket

官方文档说明: 

在公众号第三方平台建立审核经过后,微信服务器会向其“受权事件接收URL”每隔10分钟定时推送component_verify_ticket。第三方平台方在收到ticket推送后也需进行解密(详细请见【消息加解密接入指引】),接收到后必须直接返回字符串success。

咱们建议一个控制 WxOpenController 用来接受微信开放平台POST推送的消息。

咱们按照Senparc的第三方平台的Demo,先用最简单的方式保存component_verify_ticket到~/App_Data/OpenTicket/{AppId}.txt文本",固然啦也能够存入数据库或其余能够持久化的地方。

CustomThirdPartyMessageHandlers 用于接收微信开放平台推送的消息并解析。有了解过Senparc相关组件的盆友们,估计应该都知道这个类的用处,这里很少说了,详细说明看文档。

核心代码,与Senparc官网的代码暂时没多大区别。咱们主要是为后面处理小程序的受权及业务作准备工做。

 appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SenparcWeixinSetting": {
    //公众号
    "Token": "***",
    "EncodingAESKey": "**********************",
    "WeixinAppId": "*********************",
    "WeixinAppSecret": "**************************",
    //开放平台
    "Component_Appid": "***************************",
    "Component_Secret": "***********************************"


  }
}

WxOpenController.cs

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Senparc.Weixin;
using Senparc.Weixin.Entities;
using Senparc.Weixin.MP.MvcExtension;
using Senparc.Weixin.Open.Entities.Request;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZY.WxOpen.WebHost.MessageHandlers.ThirdPartyMessageHandlers;
using ZY.WxOpen.WebHost.Utilities;

namespace ZY.WxOpen.WebHost.Controllers
{
    public class WxOpenController : Controller
    {
        readonly Func<string> _getRandomFileName = () => DateTime.Now.ToString("yyyyMMdd-HHmmss") + Guid.NewGuid().ToString("n").Substring(0, 6);
        //微信的全局配置,根据Senparc的官网Demo进行配置
        private readonly SenparcWeixinSetting _senparcWeixinSetting;
        //第三方平台的APPid
        private string componentAppid;
        //第三方平台的配置的token
        private string token;
        //第三方平台的配置的加密key
        private string encodingAESKey;
        private readonly IHostingEnvironment _env;

        public WxOpenController(IHostingEnvironment env,
            IOptions<SenparcWeixinSetting> senparcWeixinSetting)
        {
            _env = env;
            _senparcWeixinSetting = senparcWeixinSetting.Value;
            componentAppid = _senparcWeixinSetting.Component_Appid;
            token = _senparcWeixinSetting.Token;
            encodingAESKey = _senparcWeixinSetting.EncodingAESKey;
        }
        [ActionName("Index")]
        public ActionResult Index()
        {
            return Content("测试");
        }
        [HttpPost]
        [ActionName("Index")]
        public ActionResult Post(PostModel postModel/*,[FromBody]string requestXml*/)
        {
            #region 打包 PostModel 信息
            postModel.AppId = componentAppid;
            postModel.Token = token;//根据本身后台的设置保持一致
            postModel.EncodingAESKey = encodingAESKey;//根据本身后台的设置保持一致

            #endregion
            //配置日志输出
            var logPath = Server.GetMapPath(string.Format("~/App_Data/Open/{0}/", DateTime.Now.ToString("yyyy-MM-dd")));
            if (!Directory.Exists(logPath))
            {
                Directory.CreateDirectory(logPath);
            }

            string body = new StreamReader(Request.Body).ReadToEnd();
            byte[] requestData = Encoding.UTF8.GetBytes(body);
            Stream inputStream = new MemoryStream(requestData);
            try
            {

                var messageHandler = new CustomThirdPartyMessageHandler(inputStream, postModel);


                #region 记录 Request 日志

                //测试时可开启此记录,帮助跟踪数据,使用前请确保App_Data文件夹存在,且有读写权限。

                var requestDocumentFileName = Path.Combine(logPath, string.Format("{0}_Request_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
                var ecryptRequestDocumentFileName = Path.Combine(logPath, string.Format("{0}_Request_Ecrypt_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));

                using (FileStream fs = new FileStream(requestDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
                {
                    messageHandler.RequestDocument.Save(fs);
                }

                using (FileStream fs = new FileStream(ecryptRequestDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
                {
                    messageHandler.EcryptRequestDocument.Save(fs);
                }




                #endregion

                //执行微信处理过程
                messageHandler.Execute();

                #region 记录 Response 日志

                //测试时可开启,帮助跟踪数据

                //if (messageHandler.ResponseDocument == null)
                //{
                //    throw new Exception(messageHandler.RequestDocument.ToString());
                //}

                var responseDocumentFileName = Path.Combine(logPath, string.Format("{0}_Response_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
                var ecryptResponseDocumentFileName = Path.Combine(logPath, string.Format("{0}_Response_Final_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));

                if (messageHandler.ResponseMessageText != null)
                {
                    using (FileStream fs = new FileStream(responseDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
                    {
                        byte[] bytes = Encoding.UTF8.GetBytes(messageHandler.ResponseMessageText);
                        try
                        {
                            //设定书写的开始位置为文件的末尾  
                            fs.Position = fs.Length;
                            //将待写入内容追加到文件末尾  
                            fs.Write(bytes, 0, bytes.Length);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("文件打开失败{0}", ex.ToString());
                        }

                    }
                }



                #endregion`

                return new FixWeixinBugWeixinResult(messageHandler.ResponseMessageText);//为了解决官方微信5.0软件换行bug暂时添加的方法,平时用下面一个方法便可
            }
            catch (Exception ex)
            {
                #region 异常处理
                WeixinTrace.Log("MessageHandler错误:{0}", ex.Message);


                using (var fs = new FileStream(Server.GetMapPath("~/App_Data/Error_" + _getRandomFileName() + ".txt"), FileMode.CreateNew, FileAccess.ReadWrite))
                {
                    using (TextWriter tw = new StreamWriter(fs))
                    {
                        tw.WriteLine("ExecptionMessage:" + ex.Message);
                        tw.WriteLine(ex.Source);
                        tw.WriteLine(ex.StackTrace);
                        //tw.WriteLine("InnerExecptionMessage:" + ex.InnerException.Message);
                        tw.WriteLine("ExecptionMessage:" + ex.ToString());


                        if (ex.InnerException != null)
                        {
                            tw.WriteLine("========= InnerException =========");
                            tw.WriteLine(ex.InnerException.Message);
                            tw.WriteLine(ex.InnerException.Source);
                            tw.WriteLine(ex.InnerException.StackTrace);
                        }

                        tw.Flush();
                        //tw.Close();
                    }
                }
                return Content("");
                #endregion
            }
        }
    }
}

 CustomThirdPartyMessageHandler.cs



using Senparc.Weixin.Open; using System.IO; using Senparc.Weixin; using Senparc.Weixin.Open.Entities.Request; using ZY.WxOpen.WebHost.Utilities; namespace ZY.WxOpen.WebHost.MessageHandlers.ThirdPartyMessageHandlers { /// <summary> /// 主要用于消息的处理 /// </summary> public class CustomThirdPartyMessageHandler : ThirdPartyMessageHandler { public CustomThirdPartyMessageHandler(Stream inputStream, PostModel encryptPostModel) : base(inputStream, encryptPostModel) { } /// <summary> /// 接收微信开放平台每10分钟推送的ComponentVerifyTicket,注意:ComponentVerifyTicket很重要 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override string OnComponentVerifyTicketRequest(RequestMessageComponentVerifyTicket requestMessage) { var openTicketPath = Server.GetMapPath("~/App_Data/OpenTicket"); if (!Directory.Exists(openTicketPath)) { Directory.CreateDirectory(openTicketPath); } //记录ComponentVerifyTicket(也能够存入数据库或其余能够持久化的地方) using (FileStream fs = new FileStream(Path.Combine(openTicketPath, string.Format("{0}.txt", RequestMessage.AppId)), FileMode.OpenOrCreate, FileAccess.ReadWrite)) { using (TextWriter tw = new StreamWriter(fs)) { tw.Write(requestMessage.ComponentVerifyTicket); tw.Flush(); //tw.Close(); } } return base.OnComponentVerifyTicketRequest(requestMessage); } /// <summary> /// 受权取消 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> public override string OnUnauthorizedRequest(RequestMessageUnauthorized requestMessage) { WeixinTrace.SendCustomLog("提示", $"受权取消" + requestMessage.AuthorizerAppid); //若是须要同步用户是否取消受权,可在此接收信息并进行取消受权业务处理 //取消受权 return base.OnUnauthorizedRequest(requestMessage); } } }

 

经过以上两个核心的类,拿到微信开放平台的大门钥匙ComponentVerifyTicket,准备工做完成了,后续就是咱们须要作的业务对接。

下一篇会讲解受权及业务对接。

小程序或者公众号受权给第三方平台的技术实现流程比较简单,以公众号为例,以下图所示:

 

 

如感兴趣请多关注或者点击连接加入群聊【微信小程序】:https://jq.qq.com/?_wv=1027&k=5PnrL3m 或 搜QQ群号:397185987

相关文章
相关标签/搜索