【小程序】基于.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,微信小程序培训,能够快速赚钱 做培训的肯定首先赚 ...
随机推荐
- 【转】Selenium2学习路线
课程大纲:第一部分:基础入门 第一课: SELENIUM2的原理介绍及环境搭建本节课主要讲解SELENIUM2的原理,让大家了解SELENIUM2的发展历程,同时解惑大家对自动化测试中产生的一些误区. ...
- 算法导论学习之线性时间求第k小元素+堆思想求前k大元素
对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...
- 使用正則表達式的格式化与高亮显示json字符串
使用正則表達式的格式化与高亮显示json字符串 json字符串非常实用,有时候一些后台接口返回的信息是字符串格式的,可读性非常差,这个时候要是有个能够格式化并高亮显示json串的方法那就好多了,以下看 ...
- HDU 1031.Design T-Shirt【结构体二次排序】【8月21】
Design T-Shirt Problem Description Soon after he decided to design a T-shirt for our Algorithm Board ...
- 机器学习笔记之PCA-SIFT总结
不多说,直接上干货! PCA-SIFT算法在描述子构建上作了创新,主要是 将统计学中的主成分分析(PCA)应用于对描述子向量的降维,以提高匹配效率 . PCA 的原理是:一般有效信号的方差大,噪声的方 ...
- 我的kindle书单
刚刚入手kindle,希望能够持续阅读,不断进步. 列下书单,记录我的阅读足迹,更希望园友若有好书多多推荐,互相交流. # keep updating ... 我的kindle书单 book name ...
- 项目已经部署,tomcat已经启动,网址也没问题,却出现404错误
这个有可能是tomcat在初始化资源的时候发生了异常...判断tomcat是否发生异常就是看tomcat启动日志里有没有报错就行了. 另一种原因就是可能是修改了项目名称.因为web名称实际上是没有跟着 ...
- 嵌入式开发之命令行---linux下的find文件查找命令与grep文件内容查找命令
在使用linux时,经常需要进行文件查找.其中查找的命令主要有find和grep.两个命令是有区的. 区别:(1)find命令是根据文件的属性进行查找,如文件名,文件大小,所有者,所属组,是否为空,访 ...
- HDU 4277 USACO ORZ(暴力+双向枚举)
USACO ORZ Time Limit: 5000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- mongodb Failed to start LSB: An object/document-oriented dat
解决办法: cd /var/lib sudo rm -rf ./mongodb sudo mkdir mongodb sudo chown -R mongodb mongodb/ sudo servi ...