From a6f0b7232eb52163876e5fa3d48dfdb1891d4e88 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 9 Mar 2023 21:45:57 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/WechatApi/Basic_Parameters.md | 2 +- .../Basic_RequestSensitiveDataEncryption.md | 4 +- .../Basic_ResponseSensitiveDataDecryption.md | 2 +- docs/WechatTenpayV2/Basic_Parameters.md | 2 +- docs/WechatTenpayV3/Basic_Parameters.md | 6 +- .../Basic_RequestSensitiveDataEncryption.md | 2 +- .../Basic_ResponseSensitiveDataDecryption.md | 2 +- docs/WechatTenpayV3/Basic_SMAlgorithm.md | 4 +- docs/WechatTenpayV3/README.md | 4 +- docs/WechatWork/Basic_FinanceSDK.md | 198 ++++++++++++++++++ docs/WechatWork/Basic_Parameters.md | 4 +- docs/WechatWork/README.md | 5 +- .../README.md | 2 +- 13 files changed, 219 insertions(+), 18 deletions(-) create mode 100644 docs/WechatWork/Basic_FinanceSDK.md diff --git a/docs/WechatApi/Basic_Parameters.md b/docs/WechatApi/Basic_Parameters.md index f723816c..0451f551 100644 --- a/docs/WechatApi/Basic_Parameters.md +++ b/docs/WechatApi/Basic_Parameters.md @@ -12,7 +12,7 @@ ```csharp /* 以生成 wx.config() 所需参数为例 */ -var request = new Models.CgibinTicketGetTicketRequest() +var request = new CgibinTicketGetTicketRequest() { AccessToken = "微信 AccessToken" }; diff --git a/docs/WechatTenpayBusiness/Basic_RequestSensitiveDataEncryption.md b/docs/WechatTenpayBusiness/Basic_RequestSensitiveDataEncryption.md index c84b2e68..63042ffe 100644 --- a/docs/WechatTenpayBusiness/Basic_RequestSensitiveDataEncryption.md +++ b/docs/WechatTenpayBusiness/Basic_RequestSensitiveDataEncryption.md @@ -31,9 +31,9 @@ request.TBEPEncryption = new WechatTenpayBusinessRequestTBEPEncryption() 此外,本库还封装了直接加密请求中敏感信息字段的扩展方法。下面给出一个手动调用的示例: ```csharp -var request = new Models.CreateMSEPayProductApplicationRequest() +var request = new CreateMSEPayProductApplicationRequest() { - BusinessLicense = new Models.CreateMSEPayProductApplicationRequest.Types.BusinessLicense() + BusinessLicense = new CreateMSEPayProductApplicationRequest.Types.BusinessLicense() { BusinessRegisterType = "TYPE", MerchantName = "商户", diff --git a/docs/WechatTenpayBusiness/Basic_ResponseSensitiveDataDecryption.md b/docs/WechatTenpayBusiness/Basic_ResponseSensitiveDataDecryption.md index 5f1f0a00..ea6049c6 100644 --- a/docs/WechatTenpayBusiness/Basic_ResponseSensitiveDataDecryption.md +++ b/docs/WechatTenpayBusiness/Basic_ResponseSensitiveDataDecryption.md @@ -23,7 +23,7 @@ string plainText = SM4Utility.DecryptWithCBC(sm4Key, sm4IV, cipherText); 此外,本库还封装了直接解密响应中敏感信息字段的扩展方法,下面给出一个示例代码: ```csharp -var request = new Models.GetMSEPayPaymentByPaymentIdRequest(); +var request = new GetMSEPayPaymentByPaymentIdRequest(); var response = await client.ExecuteGetMSEPayPaymentByPaymentIdAsync(request); Console.WriteLine("before: {0}", response.Payee.EnterpriseName); // 此时仍是密文 diff --git a/docs/WechatTenpayV2/Basic_Parameters.md b/docs/WechatTenpayV2/Basic_Parameters.md index cc6e7a62..ef524390 100644 --- a/docs/WechatTenpayV2/Basic_Parameters.md +++ b/docs/WechatTenpayV2/Basic_Parameters.md @@ -16,7 +16,7 @@ ```csharp /* 以生成 JSAPI 调起支付所需参数为例 */ -var request = new Models.CreatePayUnifiedOrderRequest() +var request = new CreatePayUnifiedOrderRequest() { OutTradeNumber = "商户订单号", AppId = "公众号 AppId", diff --git a/docs/WechatTenpayV3/Basic_Parameters.md b/docs/WechatTenpayV3/Basic_Parameters.md index cae360a3..52d3c5a5 100644 --- a/docs/WechatTenpayV3/Basic_Parameters.md +++ b/docs/WechatTenpayV3/Basic_Parameters.md @@ -16,17 +16,17 @@ ```csharp /* 以生成 JSAPI 调起支付所需参数为例 */ -var request = new Models.CreatePayTransactionJsapiRequest() +var request = new CreatePayTransactionJsapiRequest() { OutTradeNumber = "商户订单号", AppId = "公众号 AppId", Description = "描述", NotifyUrl = "回调地址", - Amount = new Models.CreatePayTransactionJsapiRequest.Types.Amount() + Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = 0 }, - Payer = new Models.CreatePayTransactionJsapiRequest.Types.Payer() + Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = "用户 OpenId" } diff --git a/docs/WechatTenpayV3/Basic_RequestSensitiveDataEncryption.md b/docs/WechatTenpayV3/Basic_RequestSensitiveDataEncryption.md index 57fa6405..d0c078bf 100644 --- a/docs/WechatTenpayV3/Basic_RequestSensitiveDataEncryption.md +++ b/docs/WechatTenpayV3/Basic_RequestSensitiveDataEncryption.md @@ -58,7 +58,7 @@ string cipherText = RSAUtility.EncryptWithECB(publicKey, plainText); 此外,本库还封装了直接加密请求中敏感信息字段的扩展方法。下面给出一个手动调用的示例: ```csharp -var request = new Models.AddProfitSharingReceiverRequest() +var request = new AddProfitSharingReceiverRequest() { AppId = "AppId", Type = "PERSONAL_OPENID", diff --git a/docs/WechatTenpayV3/Basic_ResponseSensitiveDataDecryption.md b/docs/WechatTenpayV3/Basic_ResponseSensitiveDataDecryption.md index fbc8e06a..bbcede26 100644 --- a/docs/WechatTenpayV3/Basic_ResponseSensitiveDataDecryption.md +++ b/docs/WechatTenpayV3/Basic_ResponseSensitiveDataDecryption.md @@ -30,7 +30,7 @@ string plainText = RSAUtility.DecryptWithECB(privateKey, cipherText); 此外,本库还封装了直接解密响应中敏感信息字段的扩展方法,下面给出一个示例代码: ```csharp -var request = new Models.QueryCertificatesRequest(); +var request = new QueryCertificatesRequest(); var response = await client.ExecuteQueryCertificatesAsync(request); Console.WriteLine("before: {0}", response.CertificateList.First().EncryptCertificate.CipherText); // 此时仍是密文 diff --git a/docs/WechatTenpayV3/Basic_SMAlgorithm.md b/docs/WechatTenpayV3/Basic_SMAlgorithm.md index e4770bbc..fe72fc79 100644 --- a/docs/WechatTenpayV3/Basic_SMAlgorithm.md +++ b/docs/WechatTenpayV3/Basic_SMAlgorithm.md @@ -6,7 +6,7 @@ > > [《微信支付开发者文档 - 国密接入指引》](https://pay.weixin.qq.com/docs/merchant/development/shangmi/introduction.html) -从 v2.14.0 版本起,本库支持接入微信支付平台基于国密证书和使用 SM2/SM3/SM4 算法的 API v3 接口。 +自 v2.14.0 版本起,本库支持接入微信支付平台基于国密证书和使用 SM2/SM3/SM4 算法的 API v3 接口。 --- @@ -28,7 +28,7 @@ var client = new WechatTenpayClient(options); 接着,在获取平台证书时,需指定证书的算法类型: ```csharp -var request = new Models.QueryCertificatesRequest() +var request = new QueryCertificatesRequest() { AlgorithmType = "SM2" }; diff --git a/docs/WechatTenpayV3/README.md b/docs/WechatTenpayV3/README.md index 9a2341d8..bf5c05a3 100644 --- a/docs/WechatTenpayV3/README.md +++ b/docs/WechatTenpayV3/README.md @@ -63,11 +63,11 @@ var request = new CreatePayTransactionJsapiRequest() Description = "订单描述", ExpireTime = DateTimeOffset.Now.AddMinutes(15), NotifyUrl = "https://example.com", - Amount = new Models.CreatePayTransactionJsapiRequest.Types.Amount() + Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = 1 }, - Payer = new Models.CreatePayTransactionJsapiRequest.Types.Payer() + Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = "微信 OpenId" } diff --git a/docs/WechatWork/Basic_FinanceSDK.md b/docs/WechatWork/Basic_FinanceSDK.md new file mode 100644 index 00000000..e3b8f450 --- /dev/null +++ b/docs/WechatWork/Basic_FinanceSDK.md @@ -0,0 +1,198 @@ +## 如何接入会话内容存档 C SDK? + +--- + +> 请先自行阅读: +> +> [《企业微信开发者中心 - 服务端 API - 会话内容存档:使用前帮助》](https://developer.work.weixin.qq.com/document/path/91361) + +自 v2.16.0 版本起,本库支持接入会话内容存档 C SDK。 + +如需使用本功能,请先在企业微信管理后台中开启会话内容存档并设置相关参数。 + +--- + +### 接入前必读 + +企业微信官方仅提供了 C 语言实现的会话内容存档 SDK,且屏蔽了具体实现细节。 + +本库在此基础之上,对相关功能做了二次封装。 + +与简单的基于 P/Invoke 的调用方式相比,本库的封装更加符合 C# 项目的编程习惯,使得开发者无需关心非托管对象的内存空间开辟与释放问题,大大减轻了开发者的心智负担。 + +为了减少本库的打包体积,本库并没有内嵌 C SDK 相关的动态链接库,需要开发者手动下载。 + +- 对于 Linux 环境,你需要[下载 v1.2 版本的 C SDK for Linux](https://developer.work.weixin.qq.com/document/path/91774),解压缩并拷贝以下几个文件到你的项目根路径下,或添加至系统环境变量 _/$LD_LIBRARY_PATH/_(通常为 _/lib/_ 或 _/usr/lib/_)中: + + 1. `libWeWorkFinanceSdk_C.so` + +- 对于 Windows 环境,你需要[下载 v1.1 版本的 C SDK for Windows](https://developer.work.weixin.qq.com/document/path/91774),解压缩并拷贝以下几个文件到你的项目根路径下,或添加至系统环境变量 _%SYSTEMROOT%\System32\\_(通常为 _C:\Windows\System32\\_) 中: + + 1. `libcrypto-1_1-x64.dll` + 2. `libcurl-x64.dll` + 3. `libssl-1_1-x64.dll` + 4. `WeWorkFinanceSdk.dll` + +请注意,以上几个文件,不能重命名其文件名。 + +--- + +### 接入指引 + +#### 一、初始化 + +与初始化本库的 HTTP API 客户端的过程类似。 + +```csharp +using SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance; +using SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.Models; +using SKIT.FlurlHttpClient.Wechat.Work.SDK.Finance.Settings; + +var manager = new InMemoryEncryptionKeyManager(); +manager.AddEntry(new EncryptionKeyEntry(1, "-----BEGIN RSA PRIVATE KEY----- 消息加解密私钥 PKCS#1 PEM 内容 -----END RSA PRIVATE KEY-----")); +var options = new WechatWorkFinanceClientOptions() +{ + CorpId = "企业微信 CorpId", + SecretKey = "会话内容存档 SecretKey", + EncryptionKeyManager = manager // 密钥管理器的具体用法将在本章节下文详细介绍 +}; +var client = new WechatWorkFinanceClient(options); +``` + +#### 二、获取会话记录数据 + +```csharp +var request = new GetChatRecordsRequest() +{ + LastSequence = 0, + Limit = 100 +}; +var response = await client.ExecuteGetChatRecordsAsync(request); +if (response.IsSuccessful()) +{ + Console.WriteLine("聊天记录:" + response.RecordList); +} +else +{ + Console.WriteLine("返回值:" + response.ReturnCode); + Console.WriteLine("错误代码:" + response.ErrorCode); + Console.WriteLine("错误描述:" + response.ErrorMessage); +} +``` + +#### 三、解密会话记录数据 + +> ⚠️ 【重要说明】使用该接口需要提前在 `EncryptionKeyManager` 中存入全部消息加解密的 RSA 私钥及其对应版本号。 + +```csharp +var request = new DecryptChatRecordRequest() +{ + PublicKeyVersion = 1, // 即上一接口返回的 "RecordList[].PublicKeyVersion" 字段 + EncryptedRandomKey = "KEY", // 即上一接口返回的 "RecordList[].EncryptedRandomKey" 字段 + EncryptedChatMessage = "CIPHER" // 即上一接口返回的 "RecordList[].EncryptedChatMessage" 字段 +}; +var response = await client.ExecuteDecryptChatRecordAsync(request); +if (response.IsSuccessful()) +{ + Console.WriteLine("聊天记录:" + response.RecordList); +} +else +{ + Console.WriteLine("返回值:" + response.ReturnCode); +} +``` + +#### 四、下载媒体文件 + +在 C SDK 中,每次获取媒体文件数据,仅返回最大 512KB 的文件分片。 + +本库已经实现了自动获取全部分片、并整合到一起的功能,同时也参照官方建议实现了错误重试机制,你无需关心每个分片的具体下载过程,只需要: + +```csharp +var request = new GetMediaFileRequest() +{ + FileId = "SDK_FILE_ID" +}; +var response = await client.ExecuteGetMediaFileAsync(request); +if (response.IsSuccessful()) +{ + Console.WriteLine("文件的字节数组:" + response.FileBytes); +} +else +{ + Console.WriteLine("返回值:" + response.ReturnCode); +} +``` + +当然,如果你想手动控制下载分片的过程,你也可以: + +```csharp +var request = new GetMediaFileBufferRequest() +{ + FileId = "SDK_FILE_ID", + BufferIndex = "INDEX_BUF" +}; +var response = await client.ExecuteGetMediaFileAsync(request); +if (response.IsSuccessful()) +{ + Console.WriteLine("分片的字节数组:" + response.FileBufferBytes); + Console.WriteLine("下一次的分片索引:" + response.NextBufferIndex); + Console.WriteLine("是否已是最后一个分片:" + response.IsFinished); +} +else +{ + Console.WriteLine("返回值:" + response.ReturnCode); +} +``` + +--- + +### 常见问题 + +#### **Q1:是否可以实例化多个 `WechatWorkFinanceClient`?** + +不可以,也不需要。 + +你应该以全局单例模式使用 `WechatWorkFinanceClient`,它是线程安全的。 + +如果真的有多次实例化的场景,请务必在实例化新的对象之前、对前一个对象手动执行 `client.Dispose()` 方法以销毁,避免出现未知问题。 + +#### **Q2:密钥管理器 `EncryptionKeyManager` 有什么用?** + +在企业微信管理后台中,你需要设置消息加解密 RSA 公钥,并在获取会话记录数据后使用对应的 RSA 私钥来解密聊天记录。 + +每当你重新设置新的 RSA 公钥时,消息加解密公钥版本号就会 +1。但已经产生过的会话记录数据仍然需要使用旧的 RSA 私钥来解密(这是由于非对称加密算法的原理导致的,具体细节不在此赘述)。 + +因此,在加解密会话记录数据的过程中,可能需要多对儿 RSA 公私钥共同参与。 + +本库提供了 `EncryptionKeyManager` 这一对象,以简化解密流程。你只需在初始化时将各个版本的 RSA 私钥都存入密钥管理器中,后续调用解密会话记录数据时,本库将根据传入的公钥版本号自动选择对应的私钥: + +```csharp +manager.AddEntry(new EncryptionKeyEntry(1, "-----BEGIN RSA PRIVATE KEY----- 私钥版本 1 -----END RSA PRIVATE KEY-----")); +manager.AddEntry(new EncryptionKeyEntry(2, "-----BEGIN RSA PRIVATE KEY----- 私钥版本 2 -----END RSA PRIVATE KEY-----")); +manager.AddEntry(new EncryptionKeyEntry(3, "-----BEGIN RSA PRIVATE KEY----- 私钥版本 3 -----END RSA PRIVATE KEY-----")); +``` + +> ⚠️ 【重要说明】请尽量避免频繁重置消息加解密密钥。如果真的有需要,重置前千万不要忘记备份上一个版本的私钥,否则已经产生的会话记录数据将永远无法解密。 + +#### **Q3:官方示例中提供了诸如 `FreeSlice`、`FreeMediaData`、`DestroySdk` 等接口,该如何调用?** + +这些方法均是为了释放由 C SDK 开辟的内存空间而提供的,对于 C# 来说,这些都是非托管对象。 + +本库已经实现了自动释放非托管内存机制,开发者无需关心内存泄露问题。 + +#### **Q4:内网环境下如何使用?** + +在 C SDK 中,已经包含了 SOCK5 代理或 HTTP 代理的相关参数。 + +在使用本库时,你可以在构造得到 `WechatWorkFinanceClient` 对象时指定代理参数: + +```csharp +var options = new WechatWorkFinanceClientOptions() +{ + // 其他配置项略 + ProxyAddress = "socks5://10.0.0.1:8081", + ProxyAuthentication = "username:password" +}; +var client = new WechatWorkFinanceClient(options); +``` diff --git a/docs/WechatWork/Basic_Parameters.md b/docs/WechatWork/Basic_Parameters.md index b822ae8f..093fcf2d 100644 --- a/docs/WechatWork/Basic_Parameters.md +++ b/docs/WechatWork/Basic_Parameters.md @@ -4,7 +4,7 @@ > 请先自行阅读: > -> [企业微信 API - 客户端 API:JS-SDK 使用权限签名算法》](https://open.work.weixin.qq.com/api/doc/90000/90136/90506) +> [《企业微信开发者中心 - 客户端 API - JS-SDK:JS-SDK 使用权限签名算法》](https://open.work.weixin.qq.com/api/doc/90000/90136/90506) 你可根据官方文档的规则利用本库提供的 `SHA1Utility` 工具类自行进行签名生成。 @@ -12,7 +12,7 @@ ```csharp /* 以生成 wx.config() 所需参数为例 */ -var request = new Models.CgibinGetJsapiTicketRequest() +var request = new CgibinGetJsapiTicketRequest() { AccessToken = "企业微信应用的 AccessToken" }; diff --git a/docs/WechatWork/README.md b/docs/WechatWork/README.md index cf19bedc..e1163fb4 100644 --- a/docs/WechatWork/README.md +++ b/docs/WechatWork/README.md @@ -8,7 +8,8 @@ - 基于企业微信 API 封装。 - 支持企业内部开发、第三方应用开发、服务商代开发、智慧硬件开发四种模式。 -- 提供了企业微信 API 所需的 AES、SHA-1 等算法工具类。 +- 提供了企业微信 API 所需的 AES、RSA、SHA-1 等算法工具类。 +- 提供了企业微信会话内容存档 C SDK 的相关功能封装。 - 提供了 JS-SDK 签名、解析回调通知事件等扩展方法。 --- @@ -77,6 +78,8 @@ else - [如何生成 JS-SDK 所需的参数及签名?](./Basic_Parameters.md) +- [如何接入会话内容存档 C SDK?](./Basic_FinanceSDK.md) + - [如何自定义额外的 API 接口?](./Basic_Extensions.md) --- diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/README.md b/src/SKIT.FlurlHttpClient.Wechat.Work/README.md index 8e3c4c42..8da6f6e8 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/README.md +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/README.md @@ -11,7 +11,7 @@ - 基于企业微信 API 封装。 - 支持企业内部开发、第三方应用开发、服务商代开发、智慧硬件开发四种模式。 - 提供了企业微信 API 所需的 AES、RSA、SHA-1 等算法工具类。 -- 提供了企业微信会话内容存档 SDK 的相关功能封装。 +- 提供了企业微信会话内容存档 C SDK 的相关功能封装。 - 提供了 JS-SDK 签名、解析回调通知事件等扩展方法。 ---