【小程序】基于.NET CORE2.1 的 微信开放平台 第三方平台开发 教程一 准备工作
微信第三方平台概述
公众平台第三方平台是为了让公众号或小程序运营者,在面向垂直行业需求时,可以一键授权给第三方平台(并且可以同时授权给多家第三方),通过第三方平台来完成业务,开放给所有通过开发者资质认证后的开发者使用。
这里啰嗦一下,什么是微信第三方平台,有什么作用?
官方介绍:微信第三方平台的开放,是为了让公众号或小程序运营者,在面向垂直行业需求时,可以一键登录授权给第三方的公众号或小程序运营平台,通过第三方开发者提供的公众号或小程序第三方平台来完成相关业务。
从技术上简单来说,客户无需提供技术人员对接。无需了解微信后台开发者相关配置,比如配置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
{
"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
【小程序】基于.NET CORE2.1 的 微信开放平台 第三方平台开发 教程一 准备工作的更多相关文章
- 微信小程序-基于canvas画画涂鸦
代码地址如下:http://www.demodashi.com/demo/14461.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...
- 微信小程序基于swiper组件的tab切换
代码地址如下:http://www.demodashi.com/demo/14010.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...
- 微信小程序基于scroll-view实现锚点定位
代码地址如下:http://www.demodashi.com/demo/14009.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...
- 微信小程序-基于高德地图API实现天气组件(动态效果)
微信小程序-基于高德地图API实现天气组件(动态效果) 在社区翻腾了许久,没有找到合适的天气插件.迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用.现在分享到互联网社区中,帮助后续有 ...
- 微信小程序--基于ColorUI构建皮皮虾短视频去水印组件(仅供学习使用)
微信小程序--基于ColorUI构建皮皮虾短视频去水印组件(仅供学习使用) 没错,我是皮友,我想学习舞蹈(/doge)和瑜伽 ,要无水印的那种有助于我加深学习. 1.组件效果展示 2.组件引入准备 h ...
- 微信小程序 -- 基于 movable-view 实现拖拽排序
微信小程序 -- 基于 movable-view 实现拖拽排序 项目基于colorui样式组件 ColorUI组件库 (color-ui.com) 1.实现效果 2. 设计思路 movable-vie ...
- 小程序基于疼讯qcloud的nodejs开发服务器部署
腾讯,疼讯,很疼. 请慎重看腾讯给出的文档,最好做一个笔记. 我只能说我能力有限,在腾讯云小程序的文档中跳了n天. 最后还是觉得记录下来,以防止我的cpu过载给烧了. 此文档是对<小程序 ...
- [转]微信小程序之购物数量加减 —— 微信小程序实战商城系列(3)
本文转自:http://blog.csdn.net/michael_ouyang/article/details/70194144 我们在购买宝贝的时候,购物的数量,经常是我们需要使用的,如下所示: ...
- 微信小程序火爆,谁能在微信小程序赚取第一桶金?
2016年末,最火的话题:微信小程序.身边好多朋友蠢蠢欲动的想要借微信小程序创业,春节期间整理思绪,我们就简单说说微信的小程序可能会让哪些人赚钱: 1,微信小程序培训,能够快速赚钱 做培训的肯定首先赚 ...
随机推荐
- 巧用Drawable 实现Android UI 元素间距效果
源文地址: 巧用Drawable 实现Android UI 元素间距效果 在大部分的移动UI或者Web UI都是基于网格概念而设计的.这种网格一般都是有一些对其的方块组成,然后它们组合成为一个块.使用 ...
- 在linux命令行中编译和运行java文件
同时加载编译多个jar包和java文件 在个人平常使用或者当我们把代码部署到linux服务器上的时候,我们经常需要通过命令行编译和运行java文件,网上关于这个的方法大多是通过 javac -cp f ...
- 命令行方式下登录SqlPlus,密码含特殊字符
全撞上了! 真难侍候!oracle 12c,想登录sql plus,结果没有图形界面,直接出来个命令行.这下好了,我这个数据库,多实例,意味着登录要指定实例:密码中含有特殊字符"@" ...
- test_action
[TOP] 为什么百度校招数据挖掘工程师的笔试题目是跟数据挖掘关系不大? - 研究生生活交流 - 王道论坛,专注于计算机考研的点点滴滴! http://www.cskaoyan.com/thread- ...
- 城域网IPv6过渡技术—NAT64+DNS64 Test for IPv6 DNS64/NAT64 Compatibility Regularly
城域网IPv6过渡技术—NAT64+DNS64 - 51CTO.COM http://network.51cto.com/art/201311/419623.htm Supporting IPv6 D ...
- RFC 在OA中创建PR
创建PR:BAPI_REQUISITION_CREATE BAPI_PR_CREATE "Create Enjoy Purchase Requisistion ...
- 求两个list的交集和并集
两个list的并集,只需去除重复元素即可: 将两个list放入同一个set中即可: 两个list的交集: 1将其中一个list放入set, 2循环另一个list,每次向set塞值, 3判断set的总数 ...
- Lightoj 1024 - Eid
求n个数的最小公倍数. import java.math.*; import java.io.*; import java.util.*; import java.text.*; public cla ...
- idea output 悬浮浮动问题
参考:https://www.cnblogs.com/thinkingandworkinghard/p/6306800.html 点这个就ok
- 在 Ubuntu 16.04 中安装支持 CPU 和 GPU 的 Google TensorFlow 神经网络软件
TensorFlow 是用于机器学习任务的开源软件.它的创建者 Google 希望提供一个强大的工具以帮助开发者探索和建立基于机器学习的应用,所以他们在去年作为开源项目发布了它.TensorFlow ...