|
|
@@ -1,9 +1,11 @@
|
|
1
|
1
|
using Microsoft.Extensions.Logging;
|
|
2
|
2
|
using NLog;
|
|
3
|
3
|
using Senparc.Weixin.Context;
|
|
|
4
|
+using Senparc.Weixin.MP;
|
|
4
|
5
|
using Senparc.Weixin.MP.Entities;
|
|
5
|
6
|
using Senparc.Weixin.MP.Entities.Request;
|
|
6
|
7
|
using Senparc.Weixin.MP.MessageHandlers;
|
|
|
8
|
+using ServiceWechat.Api.CryptCode;
|
|
7
|
9
|
using System;
|
|
8
|
10
|
using System.Collections.Generic;
|
|
9
|
11
|
using System.IO;
|
|
|
@@ -13,22 +15,116 @@ using System.Xml.Linq;
|
|
13
|
15
|
|
|
14
|
16
|
namespace ServiceWechat.Api.MessageHandlers
|
|
15
|
17
|
{
|
|
16
|
|
- public partial class CustomMessageHandler : MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>
|
|
|
18
|
+ public partial class CustomMessageHandler : MessageHandler<CustomMessageContext>
|
|
17
|
19
|
{
|
|
18
|
20
|
static Logger Logger = LogManager.GetCurrentClassLogger();
|
|
19
|
21
|
|
|
|
22
|
+ private PostModel _postModel;
|
|
20
|
23
|
public CustomMessageHandler(Stream inputStream, PostModel postModel)
|
|
21
|
24
|
: base(inputStream, postModel)
|
|
22
|
25
|
{
|
|
23
|
26
|
Logger.Info($"实例化CustomMessageHandler");
|
|
|
27
|
+ _postModel = postModel;
|
|
24
|
28
|
}
|
|
25
|
|
-
|
|
26
|
|
- public CustomMessageHandler(XDocument inputStream, PostModel postModel)
|
|
27
|
|
- : base(inputStream, postModel)
|
|
|
29
|
+ /// <summary>
|
|
|
30
|
+ /// 初始化时【解密】
|
|
|
31
|
+ /// </summary>
|
|
|
32
|
+ /// <param name="postDataDocument"></param>
|
|
|
33
|
+ /// <param name="postData"></param>
|
|
|
34
|
+ /// <returns></returns>
|
|
|
35
|
+ public override XDocument Init(XDocument postDataDocument, object postData = null)
|
|
28
|
36
|
{
|
|
29
|
|
- Logger.Info($"实例化CustomMessageHandler");
|
|
|
37
|
+
|
|
|
38
|
+ //进行加密判断并处理
|
|
|
39
|
+ _postModel = postData as PostModel;
|
|
|
40
|
+ var postDataStr = postDataDocument.ToString();
|
|
|
41
|
+ Logger.Info($"Init postDataStr={postDataStr}");
|
|
|
42
|
+
|
|
|
43
|
+
|
|
|
44
|
+ XDocument decryptDoc = postDataDocument;
|
|
|
45
|
+
|
|
|
46
|
+ if (_postModel != null && postDataDocument.Root.Element("Encrypt") != null && !string.IsNullOrEmpty(postDataDocument.Root.Element("Encrypt").Value))
|
|
|
47
|
+ {
|
|
|
48
|
+ //使用了加密
|
|
|
49
|
+ UsingEcryptMessage = true;
|
|
|
50
|
+ EcryptRequestDocument = postDataDocument;
|
|
|
51
|
+
|
|
|
52
|
+ WXBizMsgCrypt msgCrype = new WXBizMsgCrypt(_postModel.Token, _postModel.EncodingAESKey, _postModel.AppId);
|
|
|
53
|
+ string msgXml = null;
|
|
|
54
|
+ var result = msgCrype.DecryptMsg(_postModel.Msg_Signature, _postModel.Timestamp, _postModel.Nonce, postDataStr, ref msgXml);
|
|
|
55
|
+
|
|
|
56
|
+ //判断result类型
|
|
|
57
|
+ if (result != 0)
|
|
|
58
|
+ {
|
|
|
59
|
+ //验证没有通过,取消执行
|
|
|
60
|
+ CancelExcute = true;
|
|
|
61
|
+ return null;
|
|
|
62
|
+ }
|
|
|
63
|
+
|
|
|
64
|
+ if (postDataDocument.Root.Element("FromUserName") != null && !string.IsNullOrEmpty(postDataDocument.Root.Element("FromUserName").Value))
|
|
|
65
|
+ {
|
|
|
66
|
+ //TODO:使用了兼容模式,进行验证即可
|
|
|
67
|
+ UsingCompatibilityModelEcryptMessage = true;
|
|
|
68
|
+ }
|
|
|
69
|
+
|
|
|
70
|
+ decryptDoc = XDocument.Parse(msgXml);//完成解密
|
|
|
71
|
+ }
|
|
|
72
|
+
|
|
|
73
|
+ RequestMessage = RequestMessageFactory.GetRequestEntity(decryptDoc);
|
|
|
74
|
+ if (UsingEcryptMessage)
|
|
|
75
|
+ {
|
|
|
76
|
+ RequestMessage.Encrypt = postDataDocument.Root.Element("Encrypt").Value;
|
|
|
77
|
+ }
|
|
|
78
|
+
|
|
|
79
|
+
|
|
|
80
|
+ //TODO:分布式系统中本地的上下文会有同步问题,需要同步使用远程的储存
|
|
|
81
|
+ if (WeixinContextGlobal.UseWeixinContext)
|
|
|
82
|
+ {
|
|
|
83
|
+
|
|
|
84
|
+ var omit = OmitRepeatedMessageFunc == null || OmitRepeatedMessageFunc(RequestMessage);
|
|
|
85
|
+
|
|
|
86
|
+ lock (WeixinContextGlobal.OmitRepeatLock)//TODO:使用分布式锁
|
|
|
87
|
+ {
|
|
|
88
|
+ #region 消息去重
|
|
|
89
|
+
|
|
|
90
|
+ if (omit &&
|
|
|
91
|
+ OmitRepeatedMessage &&
|
|
|
92
|
+ CurrentMessageContext.RequestMessages.Count > 0
|
|
|
93
|
+ //&& !(RequestMessage is RequestMessageEvent_Merchant_Order)批量订单的MsgId可能会相同
|
|
|
94
|
+ )
|
|
|
95
|
+ {
|
|
|
96
|
+ //lastMessage必定有值(除非极端小的过期时间条件下,几乎不可能发生)
|
|
|
97
|
+ var lastMessage = CurrentMessageContext.RequestMessages[CurrentMessageContext.RequestMessages.Count - 1];
|
|
|
98
|
+
|
|
|
99
|
+ if (
|
|
|
100
|
+ //使用MsgId去重
|
|
|
101
|
+ (lastMessage.MsgId != 0 && lastMessage.MsgId == RequestMessage.MsgId)
|
|
|
102
|
+ //使用CreateTime去重(OpenId对象已经是同一个)
|
|
|
103
|
+ || (lastMessage.MsgId == RequestMessage.MsgId
|
|
|
104
|
+ && lastMessage.CreateTime == RequestMessage.CreateTime
|
|
|
105
|
+ && lastMessage.MsgType == RequestMessage.MsgType)
|
|
|
106
|
+ )
|
|
|
107
|
+ {
|
|
|
108
|
+ CancelExcute = true;//重复消息,取消执行
|
|
|
109
|
+ MessageIsRepeated = true;
|
|
|
110
|
+ }
|
|
|
111
|
+ }
|
|
|
112
|
+
|
|
|
113
|
+ #endregion
|
|
|
114
|
+
|
|
|
115
|
+ //在消息没有被去重的情况下记录上下文
|
|
|
116
|
+ if (!MessageIsRepeated)
|
|
|
117
|
+ {
|
|
|
118
|
+ WeixinContext.InsertMessage(RequestMessage);
|
|
|
119
|
+ }
|
|
|
120
|
+ }
|
|
|
121
|
+ }
|
|
|
122
|
+
|
|
|
123
|
+ Logger.Info($"接收用户消息调用RecieveMsg =【{ decryptDoc }】");
|
|
|
124
|
+ return decryptDoc;
|
|
30
|
125
|
}
|
|
31
|
126
|
|
|
|
127
|
+
|
|
32
|
128
|
/// <summary>
|
|
33
|
129
|
/// 默认回复
|
|
34
|
130
|
/// </summary>
|
|
|
@@ -36,49 +132,13 @@ namespace ServiceWechat.Api.MessageHandlers
|
|
36
|
132
|
/// <returns></returns>
|
|
37
|
133
|
public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
|
|
38
|
134
|
{
|
|
39
|
|
- var responseMessage = this.CreateResponseMessage<ResponseMessageText>(); //ResponseMessageText也可以是News等其他类型
|
|
|
135
|
+ var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(RequestMessage);
|
|
40
|
136
|
Logger.Info($"我是默认的自动回复 么么哒~~~。");
|
|
41
|
137
|
responseMessage.Content = "我是默认的自动回复 么么哒~~~。";
|
|
42
|
138
|
return responseMessage;
|
|
43
|
139
|
}
|
|
44
|
140
|
|
|
45
|
141
|
|
|
46
|
|
- public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage)
|
|
47
|
|
- {
|
|
48
|
|
- var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
|
|
49
|
|
- //responseMessage.Content = "您的OpenID是:" + responseMessage.FromUserName+".\r\n您发送的文字是:"+requestMessage.Content;
|
|
50
|
|
- if (requestMessage.Content == "ID")
|
|
51
|
|
- responseMessage.Content = "您的OpenID是:" + responseMessage.FromUserName;
|
|
52
|
|
- if (requestMessage.Content == "天气")
|
|
53
|
|
- responseMessage.Content = "抱歉,还未开通此功能!";
|
|
54
|
|
- return responseMessage;
|
|
55
|
|
- }
|
|
56
|
|
-
|
|
57
|
|
-
|
|
58
|
|
- /// <summary>
|
|
59
|
|
- /// 处理用户发来的文本信息
|
|
60
|
|
- /// </summary>
|
|
61
|
|
- /// <param name="requestMessage"></param>
|
|
62
|
|
- /// <returns></returns>
|
|
63
|
|
- //public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage)
|
|
64
|
|
- //{
|
|
65
|
|
-
|
|
66
|
|
- // //requestMessage.FromUserName也可以直接写成base.WeixinOpenId
|
|
67
|
|
- // var openId = base.WeixinOpenId;
|
|
68
|
|
- // //客户发来的文本信息
|
|
69
|
|
- // var content = requestMessage.Content;
|
|
70
|
|
-
|
|
71
|
|
- // Logger.Info($"您的OpenID是{openId}。\r\n您发送了文字信息:{content}, requestMessage.MsgId={requestMessage.MsgId},requestMessage.MsgId={requestMessage.CreateTime}");
|
|
72
|
|
- // //【TODO:查询已配置的文本回复信息】
|
|
73
|
|
-
|
|
74
|
|
- // var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
|
|
75
|
|
- // responseMessage.Content = $"您的OpenID是{openId}。\r\n您发送了文字信息:{content}, requestMessage.MsgId={requestMessage.MsgId},requestMessage.MsgId={requestMessage.CreateTime}";
|
|
76
|
|
- // Logger.Info($"responseMessage.FromUserName = {responseMessage.FromUserName} responseMessage.MsgType={responseMessage.MsgType},responseMessage.ToUserName={responseMessage.ToUserName}");
|
|
77
|
|
- // return responseMessage;
|
|
78
|
|
-
|
|
79
|
|
-
|
|
80
|
|
- //}
|
|
81
|
|
-
|
|
82
|
142
|
|
|
83
|
143
|
public override void OnExecuting()
|
|
84
|
144
|
{
|
|
|
@@ -98,5 +158,30 @@ namespace ServiceWechat.Api.MessageHandlers
|
|
98
|
158
|
base.OnExecuted();
|
|
99
|
159
|
CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1;
|
|
100
|
160
|
}
|
|
|
161
|
+
|
|
|
162
|
+ public override XDocument FinalResponseDocument
|
|
|
163
|
+ {
|
|
|
164
|
+ get
|
|
|
165
|
+ {
|
|
|
166
|
+ Logger.Info($"ResponseDocument");
|
|
|
167
|
+ if (ResponseDocument == null)
|
|
|
168
|
+ {
|
|
|
169
|
+ Logger.Info($"ResponseDocument=null");
|
|
|
170
|
+ return null;
|
|
|
171
|
+ }
|
|
|
172
|
+
|
|
|
173
|
+ var timeStamp = _postModel.Timestamp;
|
|
|
174
|
+ var nonce = _postModel.Nonce;
|
|
|
175
|
+
|
|
|
176
|
+ WXBizMsgCrypt msgCrype = new WXBizMsgCrypt(_postModel.Token, _postModel.EncodingAESKey, _postModel.AppId);
|
|
|
177
|
+ string finalResponseXml = null;
|
|
|
178
|
+ msgCrype.EncryptMsg(ResponseDocument.ToString(), timeStamp, nonce, ref finalResponseXml);//TODO:这里官方的方法已经把EncryptResponseMessage对应的XML输出出来了
|
|
|
179
|
+ Logger.Info($"ResponseDocument.ToString() =【{ ResponseDocument.ToString() }】");
|
|
|
180
|
+ Logger.Info($"finalResponseXml =【{ finalResponseXml }】");
|
|
|
181
|
+ return XDocument.Parse(finalResponseXml);
|
|
|
182
|
+
|
|
|
183
|
+ }
|
|
|
184
|
+
|
|
|
185
|
+ }
|
|
101
|
186
|
}
|
|
102
|
|
-}
|
|
|
187
|
+}
|