diff --git a/docs/WechatApi/Advanced_EventDataDeserialization.md b/docs/WechatApi/Advanced_EventDataDeserialization.md index 250efa9b..2b913fd3 100644 --- a/docs/WechatApi/Advanced_EventDataDeserialization.md +++ b/docs/WechatApi/Advanced_EventDataDeserialization.md @@ -5,11 +5,11 @@ 对于微信推送过来的回调通知事件,本库封装了直接解析成事件模型的扩展方法,下面给出一个示例: ```csharp -/* 如果是 JSON 格式的通知内容 */ +/* 如果是 JSON 格式的通知内容,以 wxa_media_check 事件为例 */ string callbackJson = "{ ... }"; var callbackModel = client.DeserializeEventFromJson(callbackJson); -/* 如果是 XML 格式的通知内容 */ +/* 如果是 XML 格式的通知内容,以 text 事件为例 */ string callbackXml = " ... "; var callbackModel = client.DeserializeEventFromXml(callbackXml); ``` @@ -18,6 +18,28 @@ var callbackModel = client.DeserializeEventFromXml(call --- +### 事件类型: + +由于微信会将全部事件推送到同一个回调通知地址上,开发者需要根据事件类型才能决定如何反序列化。 + +这里给出两种解决方案。 + +一种是利用 `System.Xml.Linq`: + +```csharp +XDocument xDoc = XDocument.Parse(callbackXml); +string msgType = xDoc.Root?.Element("MsgType")?.Value?.ToUpper(); +``` + +另一种是利用本库的扩展方法: + +```csharp +WechatApiEvent eventModel = client.DeserializeEventFromXml(callbackXml); +string msgType = eventModel.MessageType?.ToUpper(); +``` + +--- + ### 安全模式: 在安全模式下,微信公众平台使用了一种特殊的 AES 算法对回调通知事件加密。 @@ -56,7 +78,7 @@ var replyModel = new Events.TextMessageReply() { ToUserName = "接收方 OpenId", FromUserName = "开发者 GhId", - MessageType = "text", + MessageType = "text", Content = "被动回复的文本内容", CreateTimestamp = 1234567890 }; @@ -69,4 +91,4 @@ string replyXml = client.SerializeEventToXml(replyModel); string replyXml = client.SerializeEventToXml(replyModel, safety: true); ``` -完整的被动回复模型定义可以参考项目目录下的 _src/SKIT.FlurlHttpClient.Wechat.Api/Events/MpReply_ 目录。 \ No newline at end of file +完整的被动回复模型定义可以参考项目目录下的 _src/SKIT.FlurlHttpClient.Wechat.Api/Events/MpReply_ 目录。 diff --git a/docs/WechatApi/README.md b/docs/WechatApi/README.md index 2c86f3ef..a1e032c8 100644 --- a/docs/WechatApi/README.md +++ b/docs/WechatApi/README.md @@ -179,6 +179,8 @@ else - [如何解析回调通知事件?](./Advanced_EventDataDeserialization.md) +- [如何验证回调通知事件签名?](./Advanced_EventDataSignatureVerification.md) + - [如何生成 JS-SDK 初始化时所需的参数及签名?](./Advanced_JSSDK.md) - [如何扩展额外的 API?](./Advanced_Extensions.md) diff --git a/docs/WechatWork/Advanced_EventDataDeserialization.md b/docs/WechatWork/Advanced_EventDataDeserialization.md index 423f6f25..19358d0a 100644 --- a/docs/WechatWork/Advanced_EventDataDeserialization.md +++ b/docs/WechatWork/Advanced_EventDataDeserialization.md @@ -2,18 +2,24 @@ --- -你可根据官方文档的规则利用本库提供的 `WxBizMsgCryptor` 工具类自行解密回调通知事件的敏感信息。 - -对于解密后得到的原始数据,本库封装了直接解析成事件模型的扩展方法,下面给出一个示例: +对于微信推送过来的回调通知事件,本库封装了直接解析成事件模型的扩展方法,下面给出一个示例: ```csharp -/* 如果是 JSON 格式的通知内容 */ +/* 如果是 JSON 格式的通知内容,以 add_schedule 事件为例 */ string callbackJson = "{ ... }"; var callbackModel = client.DeserializeEventFromJson(callbackJson); -/* 如果是 XML 格式的通知内容 */ +/* 如果是 XML 格式的通知内容,以 text 事件为例 */ string callbackXml = " ... "; var callbackModel = client.DeserializeEventFromXml(callbackXml); ``` 完整的回调通知模型定义可以参考项目目录下的 _src/SKIT.FlurlHttpClient.Wechat.Work/Events_ 目录。 + +--- + +### 安全模式: + +在安全模式下,微信公众平台使用了一种特殊的 AES 算法对回调通知事件加密。 + +开发者可利用本库提供的 `WxBizMsgCryptor` 工具类自行解密相关字段。 diff --git a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs index 465039c9..dd9ec531 100644 --- a/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs +++ b/samples/SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5/Controllers/WechatNotifyController.cs @@ -39,22 +39,24 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5.Controllers [Route("a-{app_id}/message-push")] public IActionResult VerifyMessage( [FromRoute(Name = "app_id")] string appId, - [FromQuery(Name = "signature")] string signature, [FromQuery(Name = "timestamp")] string timestamp, [FromQuery(Name = "nonce")] string nonce, + [FromQuery(Name = "signature")] string signature, [FromQuery(Name = "echostr")] string echoString) { // 验证服务器推送 // 文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html - var wechatAccount = _wechatOptions.Accounts?.FirstOrDefault(e => e.AppId == appId); - if (wechatAccount == null) - return Content("fail"); - - ISet set = new SortedSet() { _wechatOptions.CallbackToken, timestamp!, nonce! }; - string sign = SHA1Utility.Hash(string.Concat(set)); - if (!string.Equals(sign, signature, StringComparison.InvariantCultureIgnoreCase)) + var client = _wechatApiHttpClientFactory.Create(appId); + bool valid = client.VerifyEventSignature( + callbackTimestamp: timestamp, + callbackNonce: nonce, + callbackSignature: signature + ); + if (!valid) + { return Content("fail"); + } return Content(echoString); } @@ -71,10 +73,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Sample_Net5.Controllers string content = await reader.ReadToEndAsync(); _logger.LogInformation("接收到微信推送的数据:{0}", content); - var xDoc = XDocument.Parse(content); - string msgType = xDoc.Root!.Element("MsgType")!.Value.ToUpper(); - var client = _wechatApiHttpClientFactory.Create(appId); + var msgType = client.DeserializeEventFromXml(content).MessageType; switch (msgType) { case "TEXT":