C#开发门户及应⽤(21)-企业号的消息和事件的接收
处理及解密
在上篇随笔《》介绍了有关企业号的消息发送,官⽅特别声明消息是不⽤加密发送的。但是在回调的服务器上,也就是我们⽹站的服务器上,传过来的消息是加密的,需要我们调⽤类库对消息和事件进⾏解密操作,由于官⽅的例⼦不全,因此摸索了不少时间,最终顺利解密收到的各种消息和事件。本⽂主要介绍企业号的消息和事件的接收处理及解密操作。
1、企业号回调模式的设置
和⼀样,企业号如果需要进⾏⼆次开发,也是需要在后台设置好对应的回调参数,如下界⾯所⽰。
设置好这些后,检查通过后,我们就可以在⾃⼰应⽤服务器上进⾏消息的收发操作了。
在回调的消息⼊⼝处,我们需要对POST数据和普通的GET数据进⾏分开处理,GET数据是⾃⾝的验证处理,POST数据是消息的交互操作。
///<summary>
///企业号回调信息接⼝。统⼀接收并处理信息的⼊⼝。
///</summary>
public class corpapi : IHttpHandler
{
///<summary>
///处理企业号的信息
///</summary>
///<param name="context"></param>
public void ProcessRequest(HttpContext context)
{
上⾯我们定义了⼀个⼀般应⽤处理程序来对消息进⾏处理。
然后我们分开不同的消息类型(POST、GET ⽅式),针对性的进⾏处理。
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);
}
2、回调消息的验证
下⾯是对于回调模式,验证URL的说明。
验证URL有效性
当你提交以上信息时,企业号将发送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;
}
3、企业号的消息处理
上⾯介绍了,企业号对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#开发门户及应⽤》系列感兴趣,可以关注我的其他⽂章,系列随笔如下所⽰: