【小程序】基於.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

相關文章
相關標籤/搜索