mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-04-05 17:37:54 +08:00
feat(work): 异步的消息加解密密钥管理器
This commit is contained in:
parent
07d65882ff
commit
a536d5049c
@ -17,6 +17,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
/// </summary>
|
||||
public string PrivateKey { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <param name="privateKey"></param>
|
||||
[Newtonsoft.Json.JsonConstructor]
|
||||
[System.Text.Json.Serialization.JsonConstructor]
|
||||
public EncryptionKeyEntry(int version, string privateKey)
|
||||
@ -32,12 +37,14 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
PrivateKey = privateKey;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(EncryptionKeyEntry other)
|
||||
{
|
||||
return int.Equals(Version, other.Version) &&
|
||||
string.Equals(PrivateKey, other.PrivateKey);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
@ -48,20 +55,23 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
return Equals((EncryptionKeyEntry)obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
return (Version.GetHashCode(), PrivateKey?.GetHashCode()).GetHashCode();
|
||||
#else
|
||||
#if NETCOREAPP || NET5_0_OR_GREATER
|
||||
return HashCode.Combine(Version.GetHashCode(), PrivateKey?.GetHashCode());
|
||||
#else
|
||||
return (Version.GetHashCode(), PrivateKey?.GetHashCode()).GetHashCode();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator ==(EncryptionKeyEntry left, EncryptionKeyEntry right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(EncryptionKeyEntry left, EncryptionKeyEntry right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
|
@ -1,45 +1,70 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// 企业微信会话内容存档的消息加解密密钥管理器接口。
|
||||
/// </summary>
|
||||
public abstract class EncryptionKeyManager
|
||||
public interface IEncryptionKeyManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取存储的全部消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract IEnumerable<EncryptionKeyEntry> AllEntries();
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
public abstract void AddEntry(EncryptionKeyEntry entry);
|
||||
void AddEntry(EncryptionKeyEntry entry);
|
||||
|
||||
/// <summary>
|
||||
/// 根据版本号获取消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <returns></returns>
|
||||
public abstract EncryptionKeyEntry? GetEntry(int version);
|
||||
EncryptionKeyEntry? GetEntry(int version);
|
||||
|
||||
/// <summary>
|
||||
/// 根据版本号移除消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool RemoveEntry(int version);
|
||||
bool RemoveEntry(int version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一个基于内存实现的 <see cref="EncryptionKeyManager"/>。
|
||||
/// 企业微信会话内容存档的消息加解密密钥管理器接口。
|
||||
/// </summary>
|
||||
public class InMemoryEncryptionKeyManager : EncryptionKeyManager
|
||||
public interface IEncryptionKeyManagerAsync : IEncryptionKeyManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步添加一个消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
Task AddEntryAsync(EncryptionKeyEntry entry, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据版本号获取消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<EncryptionKeyEntry?> GetEntryAsync(int version, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据版本号移除消息加解密密钥实体。
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> RemoveEntryAsync(int version, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一个基于内存实现的 <see cref="IEncryptionKeyManager"/>。
|
||||
/// </summary>
|
||||
public sealed class InMemoryEncryptionKeyManager : IEncryptionKeyManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<int, EncryptionKeyEntry> _dict;
|
||||
|
||||
@ -48,20 +73,14 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
_dict = new ConcurrentDictionary<int, EncryptionKeyEntry>();
|
||||
}
|
||||
|
||||
public override IEnumerable<EncryptionKeyEntry> AllEntries()
|
||||
public void AddEntry(EncryptionKeyEntry entry)
|
||||
{
|
||||
return _dict.Values.ToArray();
|
||||
_dict.AddOrUpdate(entry.Version, (_) => entry, (_, _) => entry);
|
||||
}
|
||||
|
||||
public override void AddEntry(EncryptionKeyEntry entry)
|
||||
public EncryptionKeyEntry? GetEntry(int version)
|
||||
{
|
||||
_dict.TryRemove(entry.Version, out _);
|
||||
_dict.TryAdd(entry.Version, entry);
|
||||
}
|
||||
|
||||
public override EncryptionKeyEntry? GetEntry(int version)
|
||||
{
|
||||
if (_dict.TryGetValue(version, out var entry))
|
||||
if (_dict.TryGetValue(version, out EncryptionKeyEntry entry))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
@ -69,7 +88,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool RemoveEntry(int version)
|
||||
public bool RemoveEntry(int version)
|
||||
{
|
||||
return _dict.TryRemove(version, out _);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance
|
||||
{
|
||||
using SKIT.FlurlHttpClient.Primitives;
|
||||
using SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.InteropServices;
|
||||
using SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance.Settings;
|
||||
|
||||
/// <summary>
|
||||
/// 一个企业微信会话内容存档 API HTTP 客户端。
|
||||
@ -28,12 +29,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的企业微信会话内容存档凭证。
|
||||
/// </summary>
|
||||
public Settings.Credentials Credentials { get; }
|
||||
public Credentials Credentials { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的企业微信会话内容存档消息加解密密钥管理器。
|
||||
/// </summary>
|
||||
public Settings.EncryptionKeyManager EncryptionKeyManager { get; }
|
||||
public IEncryptionKeyManager EncryptionKeyManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用指定的配置项初始化 <see cref="WechatWorkFinanceClient"/> 类的新实例。
|
||||
@ -44,7 +45,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance
|
||||
{
|
||||
if (options is null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
Credentials = new Settings.Credentials(options);
|
||||
Credentials = new Credentials(options);
|
||||
EncryptionKeyManager = options.EncryptionKeyManager;
|
||||
|
||||
_timeout = options.Timeout;
|
||||
@ -190,13 +191,15 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance
|
||||
|
||||
EnsureInitialized();
|
||||
|
||||
return Task.Run(() =>
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
string encryptKey;
|
||||
|
||||
try
|
||||
{
|
||||
Settings.EncryptionKeyEntry? encryptionKeyEntry = EncryptionKeyManager.GetEntry(request.PublicKeyVersion);
|
||||
EncryptionKeyEntry? encryptionKeyEntry = (EncryptionKeyManager is IEncryptionKeyManagerAsync asyncMananger)
|
||||
? await asyncMananger.GetEntryAsync(request.PublicKeyVersion, cancellationToken).ConfigureAwait(false)
|
||||
: EncryptionKeyManager.GetEntry(request.PublicKeyVersion);
|
||||
if (!encryptionKeyEntry.HasValue)
|
||||
throw new WechatWorkFinanceException($"Failed to decrypt random key of the encrypted chat data, because there is no private key matched the verion: \"{request.PublicKeyVersion}\".");
|
||||
|
||||
|
@ -35,6 +35,6 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.ExtendedSDK.Finance
|
||||
/// 获取或设置企业微信会话内容存档消息加解密密钥管理器。
|
||||
/// <para>默认值:<see cref="Settings.InMemoryEncryptionKeyManager"/></para>
|
||||
/// </summary>
|
||||
public Settings.EncryptionKeyManager EncryptionKeyManager { get; set; } = new Settings.InMemoryEncryptionKeyManager();
|
||||
public Settings.IEncryptionKeyManager EncryptionKeyManager { get; set; } = new Settings.InMemoryEncryptionKeyManager();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user