在上篇随笔《C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)》介绍了有关企业号的消息发送,官方特别声明消息是不用加密发送的。可是在回调的服务器上,也就是咱们网站的服务器上,微信传过来的消息是加密的,须要咱们调用类库对消息和事件进行解密操做,因为官方的例子不全,所以摸索了很多时间,最终顺利解密收到的各类消息和事件。本文主要介绍 微信企业号的消息和事件的接收处理及解密操做。html
和公众号同样,微信企业号若是须要进行二次开发,也是须要在后台设置好对应的回调参数,以下界面所示。api
设置好这些后,检查经过后,咱们就能够在本身微信应用服务器上进行消息的收发操做了。服务器
在回调的消息入口处,咱们须要对POST数据和普通的GET数据进行分开处理,GET数据是微信自身的验证处理,POST数据是微信消息的交互操做。微信
/// <summary> /// 企业号回调信息接口。统一接收并处理信息的入口。 /// </summary> public class corpapi : IHttpHandler { /// <summary> /// 处理企业号的信息 /// </summary> /// <param name="context"></param> public void ProcessRequest(HttpContext context) {
上面咱们定义了一个通常应用处理程序来对消息进行处理。并发
而后咱们分开不一样的消息类型(POST、GET 方式),针对性的进行处理。dom
if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST") { using (Stream stream = HttpContext.Current.Request.InputStream) { Byte[] postBytes = new Byte[stream.Length]; stream.Read(postBytes, 0, (Int32)stream.Length); postString = Encoding.UTF8.GetString(postBytes); } if (!string.IsNullOrEmpty(postString)) { Execute(postString, accountInfo); } } else { Auth(accountInfo); }
下面是微信对于回调模式,验证URL的说明。函数
验证URL有效性post
当你提交以上信息时,企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时须要作urldecode处理,不然会验证不成功。测试
参数 | 描述 | 是否必带 |
---|---|---|
msg_signature | 微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体 | 是 |
timestamp | 时间戳 | 是 |
nonce | 随机数 | 是 |
echostr | 加密的随机字符串,以msg_encrypt格式提供。须要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文 | 首次校验时必带 |
企业经过参数msg_signature对请求进行校验,若是确认这次GET请求来自企业号,那么企业应用对echostr参数解密并原样返回echostr明文(不能加引号),则接入验证生效,回调模式才能开启。网站
后续回调企业时都会在请求URL中带上以上参数(echostr除外),校验方式与首次验证URL一致。
根据上面的说明,咱们须要获取这些参数,而后调用微信提供的消息处理函数进行加解密处理。
在验证URL的Auth(accountInfo);操做里面,咱们能够看到核心的内容以下所示,就是获取到这些传递过来的参数信息,而后交给基类处理消息的签名内容。
#region 具体处理逻辑 string echoString = HttpContext.Current.Request.QueryString["echoStr"]; string signature = HttpContext.Current.Request.QueryString["msg_signature"];//企业号的 msg_signature string timestamp = HttpContext.Current.Request.QueryString["timestamp"]; string nonce = HttpContext.Current.Request.QueryString["nonce"]; string decryptEchoString = ""; if (new CorpBasicApi().CheckSignature(token, signature, timestamp, nonce, corpId, encodingAESKey, echoString, ref decryptEchoString)) { if (!string.IsNullOrEmpty(decryptEchoString)) { HttpContext.Current.Response.Write(decryptEchoString); HttpContext.Current.Response.End(); } } #endregion
验证代码部门以下所示。
/// <summary> /// 验证企业号签名 /// </summary> /// <param name="token">企业号配置的Token</param> /// <param name="signature">签名内容</param> /// <param name="timestamp">时间戳</param> /// <param name="nonce">nonce参数</param> /// <param name="corpId">企业号ID标识</param> /// <param name="encodingAESKey">加密键</param> /// <param name="echostr">内容字符串</param> /// <param name="retEchostr">返回的字符串</param> /// <returns></returns> public bool CheckSignature(string token, string signature, string timestamp, string nonce, string corpId, string encodingAESKey, string echostr, ref string retEchostr) { WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId); int result = wxcpt.VerifyURL(signature, timestamp, nonce, echostr, ref retEchostr); if (result != 0) { LogTextHelper.Error("ERR: VerifyURL fail, ret: " + result); return false; } return true; }
上面介绍了,微信企业号对URL的验证过程,还有另一个消息处理过程,就是微信服务器把消息发送给咱们本身的应用服务器进行处理的过程,咱们应用服务器须要在收到消息后,及时进行常规回复处理。
也就是下面的代码逻辑。
if (HttpContext.Current.Request.HttpMethod.ToUpper() == "POST") { using (Stream stream = HttpContext.Current.Request.InputStream) { Byte[] postBytes = new Byte[stream.Length]; stream.Read(postBytes, 0, (Int32)stream.Length); postString = Encoding.UTF8.GetString(postBytes); } if (!string.IsNullOrEmpty(postString)) { Execute(postString, accountInfo); } }
一样,咱们给微信服务器回应消息的时候,咱们也须要得到相应的参数,而后再行构造信息回答。
string echoString = HttpContext.Current.Request.QueryString["echoStr"]; string signature = HttpContext.Current.Request.QueryString["msg_signature"];//企业号的 msg_signature string timestamp = HttpContext.Current.Request.QueryString["timestamp"]; string nonce = HttpContext.Current.Request.QueryString["nonce"];
而另一些参数信息,则是来源于咱们企业号帐号的配置参数。
//获取配置参数并对加解密函数初始化 string CorpToken = accountInfo.Token; string AESKey = accountInfo.EncodingAESKey; string CorpId = accountInfo.CorpID;
而后使用微信提供的消息加解密类,就能够顺利对消息进行加解密的处理了。具体操做代码以下所示。
//根据参数信息,初始化微信对应的消息加密解密类 WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(CorpToken, AESKey, CorpId); //对收到的密文进行解析处理 string sMsg = ""; // 解析以后的明文 int flag = wxcpt.DecryptMsg(signature, timestamp, nonce, postStr, ref sMsg); if (flag == 0) { //LogTextHelper.Info("记录解密后的数据:"); //LogTextHelper.Info(sMsg);//记录解密后的数据 CorpApiDispatch dispatch = new CorpApiDispatch(); string responseContent = dispatch.Execute(sMsg); //加密后并发送 //LogTextHelper.Info(responseContent); string encryptResponse = ""; timestamp = DateTime.Now.DateTimeToInt().ToString(); wxcpt.EncryptMsg(responseContent, timestamp, nonce, ref encryptResponse, ref signature); HttpContext.Current.Response.ContentEncoding = Encoding.UTF8; HttpContext.Current.Response.Write(encryptResponse); } else { LogTextHelper.Info("解密消息失败!"); }
最终,咱们把解密完成的消息交给对应的封装类进行统一处理就能够了。
CorpApiDispatch dispatch = new CorpApiDispatch(); string responseContent = dispatch.Execute(sMsg);
这样咱们在企业号API的封装,就能够只须要关注消息如何应答的逻辑就能够了,其余的不用关心。
若是对这个《C#开发微信门户及应用》系列感兴趣,能够关注个人其余文章,系列随笔以下所示:
C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试
C#开发微信门户及应用(21)-微信企业号的消息和事件的接收处理及解密
C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)
C#开发微信门户及应用(18)-微信企业号的通信录管理开发之成员管理
C#开发微信门户及应用(17)-微信企业号的通信录管理开发之部门管理
C#开发微信门户及应用(15)-微信菜单增长扫一扫、发图片、发地理位置功能
C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据
C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍
C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息