微信第三方平台概述

公众平台第三方平台是为了让公众号或小程序运营者,在面向垂直行业需求时,可以一键授权给第三方平台(并且可以同时授权给多家第三方),通过第三方平台来完成业务,开放给所有通过开发者资质认证后的开发者使用。

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

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

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

从技术上简单来说,客户无需提供技术人员对接。无需了解微信后台开发者相关配置,比如配置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.1

数据库: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

微信开放平台准备

1、注册微信开放平台账户,并通过企业认证。

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

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

具体步骤

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

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

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

3、以小程序授权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

  1. {
  2. "Logging": {
  3. "LogLevel": {
  4. "Default": "Warning"
  5. }
  6. },
  7. "AllowedHosts": "*",
  8. "SenparcWeixinSetting": {
  9. //公众号
  10. "Token": "***",
  11. "EncodingAESKey": "**********************",
  12. "WeixinAppId": "*********************",
  13. "WeixinAppSecret": "**************************",
  14. //开放平台
  15. "Component_Appid": "***************************",
  16. "Component_Secret": "***********************************"
  17.  
  18. }
  19. }

WxOpenController.cs

  1. using Microsoft.AspNetCore.Hosting;
  2. using Microsoft.AspNetCore.Mvc;
  3. using Microsoft.Extensions.Options;
  4. using Senparc.Weixin;
  5. using Senparc.Weixin.Entities;
  6. using Senparc.Weixin.MP.MvcExtension;
  7. using Senparc.Weixin.Open.Entities.Request;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using ZY.WxOpen.WebHost.MessageHandlers.ThirdPartyMessageHandlers;
  15. using ZY.WxOpen.WebHost.Utilities;
  16.  
  17. namespace ZY.WxOpen.WebHost.Controllers
  18. {
  19. public class WxOpenController : Controller
  20. {
  21. readonly Func<string> _getRandomFileName = () => DateTime.Now.ToString("yyyyMMdd-HHmmss") + Guid.NewGuid().ToString("n").Substring(0, 6);
  22. //微信的全局配置,根据Senparc的官网Demo进行配置
  23. private readonly SenparcWeixinSetting _senparcWeixinSetting;
  24. //第三方平台的APPid
  25. private string componentAppid;
  26. //第三方平台的配置的token
  27. private string token;
  28. //第三方平台的配置的加密key
  29. private string encodingAESKey;
  30. private readonly IHostingEnvironment _env;
  31.  
  32. public WxOpenController(IHostingEnvironment env,
  33. IOptions<SenparcWeixinSetting> senparcWeixinSetting)
  34. {
  35. _env = env;
  36. _senparcWeixinSetting = senparcWeixinSetting.Value;
  37. componentAppid = _senparcWeixinSetting.Component_Appid;
  38. token = _senparcWeixinSetting.Token;
  39. encodingAESKey = _senparcWeixinSetting.EncodingAESKey;
  40. }
  41. [ActionName("Index")]
  42. public ActionResult Index()
  43. {
  44. return Content("测试");
  45. }
  46. [HttpPost]
  47. [ActionName("Index")]
  48. public ActionResult Post(PostModel postModel/*,[FromBody]string requestXml*/)
  49. {
  50. #region 打包 PostModel 信息
  51. postModel.AppId = componentAppid;
  52. postModel.Token = token;//根据自己后台的设置保持一致
  53. postModel.EncodingAESKey = encodingAESKey;//根据自己后台的设置保持一致
  54.  
  55. #endregion
  56. //配置日志输出
  57. var logPath = Server.GetMapPath(string.Format("~/App_Data/Open/{0}/", DateTime.Now.ToString("yyyy-MM-dd")));
  58. if (!Directory.Exists(logPath))
  59. {
  60. Directory.CreateDirectory(logPath);
  61. }
  62.  
  63. string body = new StreamReader(Request.Body).ReadToEnd();
  64. byte[] requestData = Encoding.UTF8.GetBytes(body);
  65. Stream inputStream = new MemoryStream(requestData);
  66. try
  67. {
  68.  
  69. var messageHandler = new CustomThirdPartyMessageHandler(inputStream, postModel);
  70.  
  71. #region 记录 Request 日志
  72.  
  73. //测试时可开启此记录,帮助跟踪数据,使用前请确保App_Data文件夹存在,且有读写权限。
  74.  
  75. var requestDocumentFileName = Path.Combine(logPath, string.Format("{0}_Request_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
  76. var ecryptRequestDocumentFileName = Path.Combine(logPath, string.Format("{0}_Request_Ecrypt_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
  77.  
  78. using (FileStream fs = new FileStream(requestDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
  79. {
  80. messageHandler.RequestDocument.Save(fs);
  81. }
  82.  
  83. using (FileStream fs = new FileStream(ecryptRequestDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
  84. {
  85. messageHandler.EcryptRequestDocument.Save(fs);
  86. }
  87.  
  88. #endregion
  89.  
  90. //执行微信处理过程
  91. messageHandler.Execute();
  92.  
  93. #region 记录 Response 日志
  94.  
  95. //测试时可开启,帮助跟踪数据
  96.  
  97. //if (messageHandler.ResponseDocument == null)
  98. //{
  99. // throw new Exception(messageHandler.RequestDocument.ToString());
  100. //}
  101.  
  102. var responseDocumentFileName = Path.Combine(logPath, string.Format("{0}_Response_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
  103. var ecryptResponseDocumentFileName = Path.Combine(logPath, string.Format("{0}_Response_Final_{1}.txt", _getRandomFileName(), messageHandler.RequestMessage.AppId));
  104.  
  105. if (messageHandler.ResponseMessageText != null)
  106. {
  107. using (FileStream fs = new FileStream(responseDocumentFileName, FileMode.CreateNew, FileAccess.ReadWrite))
  108. {
  109. byte[] bytes = Encoding.UTF8.GetBytes(messageHandler.ResponseMessageText);
  110. try
  111. {
  112. //设定书写的开始位置为文件的末尾
  113. fs.Position = fs.Length;
  114. //将待写入内容追加到文件末尾
  115. fs.Write(bytes, 0, bytes.Length);
  116. }
  117. catch (Exception ex)
  118. {
  119. Console.WriteLine("文件打开失败{0}", ex.ToString());
  120. }
  121.  
  122. }
  123. }
  124.  
  125. #endregion`
  126.  
  127. return new FixWeixinBugWeixinResult(messageHandler.ResponseMessageText);//为了解决官方微信5.0软件换行bug暂时添加的方法,平时用下面一个方法即可
  128. }
  129. catch (Exception ex)
  130. {
  131. #region 异常处理
  132. WeixinTrace.Log("MessageHandler错误:{0}", ex.Message);
  133.  
  134. using (var fs = new FileStream(Server.GetMapPath("~/App_Data/Error_" + _getRandomFileName() + ".txt"), FileMode.CreateNew, FileAccess.ReadWrite))
  135. {
  136. using (TextWriter tw = new StreamWriter(fs))
  137. {
  138. tw.WriteLine("ExecptionMessage:" + ex.Message);
  139. tw.WriteLine(ex.Source);
  140. tw.WriteLine(ex.StackTrace);
  141. //tw.WriteLine("InnerExecptionMessage:" + ex.InnerException.Message);
  142. tw.WriteLine("ExecptionMessage:" + ex.ToString());
  143.  
  144. if (ex.InnerException != null)
  145. {
  146. tw.WriteLine("========= InnerException =========");
  147. tw.WriteLine(ex.InnerException.Message);
  148. tw.WriteLine(ex.InnerException.Source);
  149. tw.WriteLine(ex.InnerException.StackTrace);
  150. }
  151.  
  152. tw.Flush();
  153. //tw.Close();
  154. }
  155. }
  156. return Content("");
  157. #endregion
  158. }
  159. }
  160. }
  161. }

CustomThirdPartyMessageHandler.cs

  1.  
  2. using Senparc.Weixin.Open;
  3. using System.IO;
  4. using Senparc.Weixin;
  5. using Senparc.Weixin.Open.Entities.Request;
  6. using ZY.WxOpen.WebHost.Utilities;
  7.  
  8. namespace ZY.WxOpen.WebHost.MessageHandlers.ThirdPartyMessageHandlers
  9. {
  10. /// <summary>
  11. /// 主要用于消息的处理
  12. /// </summary>
  13. public class CustomThirdPartyMessageHandler : ThirdPartyMessageHandler
  14. {
  15. public CustomThirdPartyMessageHandler(Stream inputStream, PostModel encryptPostModel)
  16. : base(inputStream, encryptPostModel)
  17. { }
  18.  
  19. /// <summary>
  20. /// 接收微信开放平台每10分钟推送的ComponentVerifyTicket,注意:ComponentVerifyTicket很重要
  21. /// </summary>
  22. /// <param name="requestMessage"></param>
  23. /// <returns></returns>
  24. public override string OnComponentVerifyTicketRequest(RequestMessageComponentVerifyTicket requestMessage)
  25. {
  26. var openTicketPath = Server.GetMapPath("~/App_Data/OpenTicket");
  27. if (!Directory.Exists(openTicketPath))
  28. {
  29. Directory.CreateDirectory(openTicketPath);
  30. }
  31.  
  32. //记录ComponentVerifyTicket(也可以存入数据库或其他可以持久化的地方)
  33. using (FileStream fs = new FileStream(Path.Combine(openTicketPath, string.Format("{0}.txt", RequestMessage.AppId)), FileMode.OpenOrCreate, FileAccess.ReadWrite))
  34. {
  35. using (TextWriter tw = new StreamWriter(fs))
  36. {
  37. tw.Write(requestMessage.ComponentVerifyTicket);
  38. tw.Flush();
  39. //tw.Close();
  40. }
  41. }
  42. return base.OnComponentVerifyTicketRequest(requestMessage);
  43. }
  44. /// <summary>
  45. /// 授权取消
  46. /// </summary>
  47. /// <param name="requestMessage"></param>
  48. /// <returns></returns>
  49. public override string OnUnauthorizedRequest(RequestMessageUnauthorized requestMessage)
  50. {
  51. WeixinTrace.SendCustomLog("提示", $"授权取消" + requestMessage.AuthorizerAppid);
  52. //如果需要同步用户是否取消授权,可在此接收信息并进行取消授权业务处理
  53. //取消授权
  54. return base.OnUnauthorizedRequest(requestMessage);
  55. }
  56. }
  57. }

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

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

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

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

【小程序】基于.NET CORE2.1 的 微信开放平台 第三方平台开发 教程一 准备工作的更多相关文章

  1. 微信小程序-基于canvas画画涂鸦

    代码地址如下:http://www.demodashi.com/demo/14461.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...

  2. 微信小程序基于swiper组件的tab切换

    代码地址如下:http://www.demodashi.com/demo/14010.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...

  3. 微信小程序基于scroll-view实现锚点定位

    代码地址如下:http://www.demodashi.com/demo/14009.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...

  4. 微信小程序-基于高德地图API实现天气组件(动态效果)

    微信小程序-基于高德地图API实现天气组件(动态效果) ​ 在社区翻腾了许久,没有找到合适的天气插件.迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用.现在分享到互联网社区中,帮助后续有 ...

  5. 微信小程序--基于ColorUI构建皮皮虾短视频去水印组件(仅供学习使用)

    微信小程序--基于ColorUI构建皮皮虾短视频去水印组件(仅供学习使用) 没错,我是皮友,我想学习舞蹈(/doge)和瑜伽 ,要无水印的那种有助于我加深学习. 1.组件效果展示 2.组件引入准备 h ...

  6. 微信小程序 -- 基于 movable-view 实现拖拽排序

    微信小程序 -- 基于 movable-view 实现拖拽排序 项目基于colorui样式组件 ColorUI组件库 (color-ui.com) 1.实现效果 2. 设计思路 movable-vie ...

  7. 小程序基于疼讯qcloud的nodejs开发服务器部署

        腾讯,疼讯,很疼. 请慎重看腾讯给出的文档,最好做一个笔记. 我只能说我能力有限,在腾讯云小程序的文档中跳了n天. 最后还是觉得记录下来,以防止我的cpu过载给烧了. 此文档是对<小程序 ...

  8. [转]微信小程序之购物数量加减 —— 微信小程序实战商城系列(3)

    本文转自:http://blog.csdn.net/michael_ouyang/article/details/70194144 我们在购买宝贝的时候,购物的数量,经常是我们需要使用的,如下所示: ...

  9. 微信小程序火爆,谁能在微信小程序赚取第一桶金?

    2016年末,最火的话题:微信小程序.身边好多朋友蠢蠢欲动的想要借微信小程序创业,春节期间整理思绪,我们就简单说说微信的小程序可能会让哪些人赚钱: 1,微信小程序培训,能够快速赚钱 做培训的肯定首先赚 ...

随机推荐

  1. AngularJS - $index, $event, $log

    原文: https://thinkster.io/egghead/index-event-log --------------------------------------------------- ...

  2. Java中正则Matcher类的matches()、lookAt()和find()的差别

    參考博文地址:http://www.oseye.net/user/kevin/blog/170 1.matcher():仅仅有在整个字符串全然匹配才返回true,否则返回false. 可是假设部分匹配 ...

  3. java File_encoding属性

    今天给客户发版本号,突然发现报表导出内容为空,大小0字节.感到很奇怪,由于开发的时候都好好的,打包出来怎么会出现异常. 细看才后发现是 file_encoding这个java系统属性编码方式设置导致的 ...

  4. Python不同功能的函数

    •函数作为参数 import math def add(x,y,f): return f(x) + f(y)print add(25,36,math.sqrt) •map()函数 map()是 Pyt ...

  5. 迅雷CTO李金波:致创业者的一封信

    我的创业感悟:写给正在寻找机会的你 李金波 我在迅雷的6年里,经历了许多困难.最折磨人的,是寻找人才:最惋惜的,莫过于看着优秀的人擦肩而过.今天再次创业(http://myhada.com),再次招聘 ...

  6. 阿里云 oss 小文件上传进度显示

    对阿里云OSS上传小文件时的进度,想过两个方法:一是.通过多线程监測Inputstream剩余的字节数来计算,可是由于Inputstream在两个线程中共用,假设上传线程将Inputstream关闭, ...

  7. ImageViewCoverflow

    https://github.com/Bertlk/ImageViewCoverflow https://github.com/dolphinwang/ImageCoverFlow http://ww ...

  8. 嵌入式开发之davinci--- 8148 中dsp在dsp_drv.c中的processdata()加算法出现下边缘条纹问题

    (1)问题原因 dsp在alglink_priv.c中做灰度处理发现,下面出现条纹,后面发现是cache 缓存没及时写进内存问题 (2)解决办法 for(frameId=0; frameId<f ...

  9. leetCode 81.Search in Rotated Sorted Array II (旋转数组的搜索II) 解题思路和方法

    Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this ...

  10. Entity Framework工具POCO Code First Generator的使用(参考链接:https://github.com/sjh37/EntityFramework-Reverse-POCO-Code-First-Generator)

    在使用Entity Framework过程中,有时需要借助工具生成Code First的代码,而Entity Framework Reverse POCO Code First Generator是一 ...