mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-07-15 23:13:32 +08:00
feat(wxapi): 反序列化回调通知事件时自动判定是否需要解密消息,并调整序列化回调通知应答默认为安全模式
This commit is contained in:
parent
120315f903
commit
23d9d247ef
@ -9,7 +9,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class WechatApiClientEventExtensions
|
public static class WechatApiClientEventExtensions
|
||||||
{
|
{
|
||||||
private class EncryptedWechatApiEvent
|
private class InnerEncryptedEvent
|
||||||
{
|
{
|
||||||
[Newtonsoft.Json.JsonProperty("Encrypt")]
|
[Newtonsoft.Json.JsonProperty("Encrypt")]
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("Encrypt")]
|
[System.Text.Json.Serialization.JsonPropertyName("Encrypt")]
|
||||||
@ -18,7 +18,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
[Newtonsoft.Json.JsonProperty("TimeStamp")]
|
[Newtonsoft.Json.JsonProperty("TimeStamp")]
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("TimeStamp")]
|
[System.Text.Json.Serialization.JsonPropertyName("TimeStamp")]
|
||||||
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalStringConverter))]
|
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalStringConverter))]
|
||||||
public string Timestamp { get; set; } = default!;
|
public string TimestampString { get; set; } = default!;
|
||||||
|
|
||||||
[Newtonsoft.Json.JsonProperty("Nonce")]
|
[Newtonsoft.Json.JsonProperty("Nonce")]
|
||||||
[System.Text.Json.Serialization.JsonPropertyName("Nonce")]
|
[System.Text.Json.Serialization.JsonPropertyName("Nonce")]
|
||||||
@ -29,7 +29,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
public string Signature { get; set; } = default!;
|
public string Signature { get; set; } = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TEvent InnerDeserializeEventFromJson<TEvent>(this WechatApiClient client, string callbackJson, bool safety)
|
private static TEvent InnerDeserializeEventFromJson<TEvent>(this WechatApiClient client, string callbackJson)
|
||||||
where TEvent : WechatApiEvent
|
where TEvent : WechatApiEvent
|
||||||
{
|
{
|
||||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||||
@ -37,15 +37,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (safety)
|
if (callbackJson.Contains("\"Encrypt\""))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(client.Credentials.PushEncodingAESKey))
|
InnerEncryptedEvent encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson);
|
||||||
throw new Exceptions.WechatApiEventSerializationException("Encrypt event failed, because there is no encoding AES key.");
|
|
||||||
|
|
||||||
var encryptedEvent = client.JsonSerializer.Deserialize<EncryptedWechatApiEvent>(callbackJson);
|
|
||||||
if (string.IsNullOrEmpty(encryptedEvent.EncryptedData))
|
|
||||||
throw new Exceptions.WechatApiEventSerializationException("Encrypt event failed, because of empty encrypted data.");
|
|
||||||
|
|
||||||
callbackJson = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedEvent.EncryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
|
callbackJson = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedEvent.EncryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +55,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TEvent InnerDeserializeEventFromXml<TEvent>(this WechatApiClient client, string callbackXml, bool safety)
|
private static TEvent InnerDeserializeEventFromXml<TEvent>(this WechatApiClient client, string callbackXml)
|
||||||
where TEvent : WechatApiEvent
|
where TEvent : WechatApiEvent
|
||||||
{
|
{
|
||||||
if (client == null) throw new ArgumentNullException(nameof(client));
|
if (client == null) throw new ArgumentNullException(nameof(client));
|
||||||
@ -69,12 +63,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (safety)
|
if (callbackXml.Contains("<Encrypt>") && callbackXml.Contains("</Encrypt>"))
|
||||||
{
|
{
|
||||||
if (!Utilities.WxBizMsgCryptor.TryParseXml(callbackXml, out string? encryptedXml))
|
XDocument xDocument = XDocument.Parse(callbackXml);
|
||||||
throw new Exceptions.WechatApiEventSerializationException("Encrypt event failed, because of empty encrypted data.");
|
string encryptedData = xDocument.Root.Element("Encrypt").Value;
|
||||||
|
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedData, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
|
||||||
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
|
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
|
||||||
@ -95,12 +88,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// <typeparam name="TEvent"></typeparam>
|
/// <typeparam name="TEvent"></typeparam>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="callbackJson"></param>
|
/// <param name="callbackJson"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要解密)。</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static TEvent DeserializeEventFromJson<TEvent>(this WechatApiClient client, string callbackJson, bool safety = false)
|
public static TEvent DeserializeEventFromJson<TEvent>(this WechatApiClient client, string callbackJson)
|
||||||
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IJsonSerializable, new()
|
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IJsonSerializable, new()
|
||||||
{
|
{
|
||||||
return InnerDeserializeEventFromJson<TEvent>(client, callbackJson, safety);
|
return InnerDeserializeEventFromJson<TEvent>(client, callbackJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -108,11 +100,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="callbackJson"></param>
|
/// <param name="callbackJson"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要解密)。</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static WechatApiEvent DeserializeEventFromJson(this WechatApiClient client, string callbackJson, bool safety = false)
|
public static WechatApiEvent DeserializeEventFromJson(this WechatApiClient client, string callbackJson)
|
||||||
{
|
{
|
||||||
return InnerDeserializeEventFromJson<WechatApiEvent>(client, callbackJson, safety);
|
return InnerDeserializeEventFromJson<WechatApiEvent>(client, callbackJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -121,12 +112,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// <typeparam name="TEvent"></typeparam>
|
/// <typeparam name="TEvent"></typeparam>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="callbackXml"></param>
|
/// <param name="callbackXml"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要解密)。</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static TEvent DeserializeEventFromXml<TEvent>(this WechatApiClient client, string callbackXml, bool safety = false)
|
public static TEvent DeserializeEventFromXml<TEvent>(this WechatApiClient client, string callbackXml)
|
||||||
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IXmlSerializable, new()
|
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IXmlSerializable, new()
|
||||||
{
|
{
|
||||||
return InnerDeserializeEventFromXml<TEvent>(client, callbackXml, safety);
|
return InnerDeserializeEventFromXml<TEvent>(client, callbackXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -134,11 +124,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="callbackXml"></param>
|
/// <param name="callbackXml"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要解密)。</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static WechatApiEvent DeserializeEventFromXml(this WechatApiClient client, string callbackXml, bool safety = false)
|
public static WechatApiEvent DeserializeEventFromXml(this WechatApiClient client, string callbackXml)
|
||||||
{
|
{
|
||||||
return InnerDeserializeEventFromXml<WechatApiEvent>(client, callbackXml, safety);
|
return InnerDeserializeEventFromXml<WechatApiEvent>(client, callbackXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -149,7 +138,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// <param name="callbackModel"></param>
|
/// <param name="callbackModel"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要加密)。</param>
|
/// <param name="safety">是否是安全模式(即是否需要加密)。</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string SerializeEventToJson<TEvent>(this WechatApiClient client, TEvent callbackModel, bool safety = false)
|
public static string SerializeEventToJson<TEvent>(this WechatApiClient client, TEvent callbackModel, bool safety = true)
|
||||||
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IJsonSerializable, new()
|
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IJsonSerializable, new()
|
||||||
{
|
{
|
||||||
string json;
|
string json;
|
||||||
@ -186,10 +175,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
sMsgEncrypt: cipher
|
sMsgEncrypt: cipher
|
||||||
);
|
);
|
||||||
|
|
||||||
json = client.JsonSerializer.Serialize(new EncryptedWechatApiEvent()
|
json = client.JsonSerializer.Serialize(new InnerEncryptedEvent()
|
||||||
{
|
{
|
||||||
EncryptedData = cipher,
|
EncryptedData = cipher,
|
||||||
Timestamp = timestamp,
|
TimestampString = timestamp,
|
||||||
Nonce = nonce,
|
Nonce = nonce,
|
||||||
Signature = sign
|
Signature = sign
|
||||||
});
|
});
|
||||||
@ -211,7 +200,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
/// <param name="callbackModel"></param>
|
/// <param name="callbackModel"></param>
|
||||||
/// <param name="safety">是否是安全模式(即是否需要加密)。</param>
|
/// <param name="safety">是否是安全模式(即是否需要加密)。</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string SerializeEventToXml<TEvent>(this WechatApiClient client, TEvent callbackModel, bool safety = false)
|
public static string SerializeEventToXml<TEvent>(this WechatApiClient client, TEvent callbackModel, bool safety = true)
|
||||||
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IXmlSerializable, new()
|
where TEvent : WechatApiEvent, WechatApiEvent.Serialization.IXmlSerializable, new()
|
||||||
{
|
{
|
||||||
string xml;
|
string xml;
|
||||||
@ -289,7 +278,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var encryptedEvent = client.JsonSerializer.Deserialize<EncryptedWechatApiEvent>(callbackJson);
|
var encryptedEvent = client.JsonSerializer.Deserialize<InnerEncryptedEvent>(callbackJson);
|
||||||
return Utilities.WxBizMsgCryptor.VerifySignature(
|
return Utilities.WxBizMsgCryptor.VerifySignature(
|
||||||
sToken: client.Credentials.PushToken!,
|
sToken: client.Credentials.PushToken!,
|
||||||
sTimestamp: callbackTimestamp,
|
sTimestamp: callbackTimestamp,
|
||||||
|
@ -4,8 +4,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
|||||||
{
|
{
|
||||||
public class TestCase_EventVerificationTests
|
public class TestCase_EventVerificationTests
|
||||||
{
|
{
|
||||||
[Fact(DisplayName = "测试用例:验签并解密回调数据")]
|
[Fact(DisplayName = "测试用例:验签并解密 XML 回调数据")]
|
||||||
public void TestVerifyEvent()
|
public void TestVerifyXmlEvent()
|
||||||
{
|
{
|
||||||
string callbacMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6";
|
string callbacMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6";
|
||||||
string callbacTimeStamp = "1409659813";
|
string callbacTimeStamp = "1409659813";
|
||||||
@ -19,7 +19,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests
|
|||||||
PushToken = "QDG6eK"
|
PushToken = "QDG6eK"
|
||||||
};
|
};
|
||||||
var client = new WechatApiClient(options);
|
var client = new WechatApiClient(options);
|
||||||
var eventModel = client.DeserializeEventFromXml<Events.TextMessageEvent>(callbackXml, safety: true);
|
var eventModel = client.DeserializeEventFromXml<Events.TextMessageEvent>(callbackXml);
|
||||||
|
|
||||||
Assert.True(client.VerifyEventSignatureFromXml(callbacTimeStamp, callbacNonce, callbackXml, callbacMsgSig));
|
Assert.True(client.VerifyEventSignatureFromXml(callbacTimeStamp, callbacNonce, callbackXml, callbacMsgSig));
|
||||||
Assert.Equal("text", eventModel.MessageType, ignoreCase: true);
|
Assert.Equal("text", eventModel.MessageType, ignoreCase: true);
|
||||||
|
Loading…
Reference in New Issue
Block a user