| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,6 +11,7 @@ | |||
| 11 | 11 | import me.chanjar.weixin.cp.api.WxCpMsgAuditService; | |
| 12 | 12 | import me.chanjar.weixin.cp.api.WxCpService; | |
| 13 | 13 | import me.chanjar.weixin.cp.bean.msgaudit.*; | |
| 14 | + import me.chanjar.weixin.cp.config.WxCpConfigStorage; | ||
| 14 | 15 | import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | |
| 15 | 16 | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |
| 16 | 17 | import org.apache.commons.lang3.StringUtils; | |
@@ -35,20 +36,59 @@ | |||
| 35 | 36 | public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService { | |
| 36 | 37 | private final WxCpService cpService; | |
| 37 | 38 | ||
| 39 | + /** | ||
| 40 | + * SDK初始化有效期,根据企微文档为7200秒 | ||
| 41 | + */ | ||
| 42 | + private static final int SDK_EXPIRES_TIME = 7200; | ||
| 43 | + | ||
| 38 | 44 | @Override | |
| 39 | 45 | public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, String passwd, | |
| 40 | 46 | @NonNull long timeout) throws Exception { | |
| 41 | - String configPath = cpService.getWxCpConfigStorage().getMsgAuditLibPath(); | ||
| 47 | + // 获取或初始化SDK | ||
| 48 | + long sdk = this.initSdk(); | ||
| 49 | + | ||
| 50 | + long slice = Finance.NewSlice(); | ||
| 51 | + long ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice); | ||
| 52 | + if (ret != 0) { | ||
| 53 | + Finance.FreeSlice(slice); | ||
| 54 | + throw new WxErrorException("getchatdata err ret " + ret); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // 拉取会话存档 | ||
| 58 | + String content = Finance.GetContentFromSlice(slice); | ||
| 59 | + Finance.FreeSlice(slice); | ||
| 60 | + WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content); | ||
| 61 | + if (chatDatas.getErrCode().intValue() != 0) { | ||
| 62 | + throw new WxErrorException(chatDatas.toJson()); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + chatDatas.setSdk(sdk); | ||
| 66 | + return chatDatas; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * 获取或初始化SDK,如果SDK已过期则重新初始化 | ||
| 71 | + * | ||
| 72 | + * @return sdk id | ||
| 73 | + * @throws WxErrorException 初始化失败时抛出异常 | ||
| 74 | + */ | ||
| 75 | + private synchronized long initSdk() throws WxErrorException { | ||
| 76 | + WxCpConfigStorage configStorage = cpService.getWxCpConfigStorage(); | ||
| 77 | + | ||
| 78 | + // 检查SDK是否已缓存且未过期 | ||
| 79 | + if (!configStorage.isMsgAuditSdkExpired()) { | ||
| 80 | + long cachedSdk = configStorage.getMsgAuditSdk(); | ||
| 81 | + if (cachedSdk > 0) { | ||
| 82 | + return cachedSdk; | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // SDK未初始化或已过期,需要重新初始化 | ||
| 87 | + String configPath = configStorage.getMsgAuditLibPath(); | ||
| 42 | 88 | if (StringUtils.isEmpty(configPath)) { | |
| 43 | 89 | throw new WxErrorException("请配置会话存档sdk文件的路径,不要配错了!!"); | |
| 44 | 90 | } | |
| 45 | 91 | ||
| 46 | - /** | ||
| 47 | - * 完整的文件库路径: | ||
| 48 | - * | ||
| 49 | - * /www/osfile/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll, | ||
| 50 | - * libWeWorkFinanceSdk_Java.so | ||
| 51 | - */ | ||
| 52 | 92 | // 替换斜杠 | |
| 53 | 93 | String replacePath = configPath.replace("\\", "/"); | |
| 54 | 94 | // 获取最后一个斜杠的下标,用作分割路径 | |
@@ -79,36 +119,22 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S | |||
| 79 | 119 | ||
| 80 | 120 | Finance.loadingLibraries(osLib, prefixPath); | |
| 81 | 121 | long sdk = Finance.NewSdk(); | |
| 82 | - //因为会话存档单独有个secret,优先使用会话存档的secret | ||
| 83 | - String msgAuditSecret = cpService.getWxCpConfigStorage().getMsgAuditSecret(); | ||
| 122 | + // 因为会话存档单独有个secret,优先使用会话存档的secret | ||
| 123 | + String msgAuditSecret = configStorage.getMsgAuditSecret(); | ||
| 84 | 124 | if (StringUtils.isEmpty(msgAuditSecret)) { | |
| 85 | - msgAuditSecret = cpService.getWxCpConfigStorage().getCorpSecret(); | ||
| 125 | + msgAuditSecret = configStorage.getCorpSecret(); | ||
| 86 | 126 | } | |
| 87 | - long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(), msgAuditSecret); | ||
| 127 | + long ret = Finance.Init(sdk, configStorage.getCorpId(), msgAuditSecret); | ||
| 88 | 128 | if (ret != 0) { | |
| 89 | 129 | Finance.DestroySdk(sdk); | |
| 90 | 130 | throw new WxErrorException("init sdk err ret " + ret); | |
| 91 | 131 | } | |
| 92 | 132 | ||
| 93 | - long slice = Finance.NewSlice(); | ||
| 94 | - ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice); | ||
| 95 | - if (ret != 0) { | ||
| 96 | - Finance.FreeSlice(slice); | ||
| 97 | - Finance.DestroySdk(sdk); | ||
| 98 | - throw new WxErrorException("getchatdata err ret " + ret); | ||
| 99 | - } | ||
| 100 | - | ||
| 101 | - // 拉取会话存档 | ||
| 102 | - String content = Finance.GetContentFromSlice(slice); | ||
| 103 | - Finance.FreeSlice(slice); | ||
| 104 | - WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content); | ||
| 105 | - if (chatDatas.getErrCode().intValue() != 0) { | ||
| 106 | - Finance.DestroySdk(sdk); | ||
| 107 | - throw new WxErrorException(chatDatas.toJson()); | ||
| 108 | - } | ||
| 133 | + // 缓存SDK | ||
| 134 | + configStorage.updateMsgAuditSdk(sdk, SDK_EXPIRES_TIME); | ||
| 135 | + log.debug("初始化会话存档SDK成功,sdk={}", sdk); | ||
| 109 | 136 | ||
| 110 | - chatDatas.setSdk(sdk); | ||
| 111 | - return chatDatas; | ||
| 137 | + return sdk; | ||
| 112 | 138 | } | |
| 113 | 139 | ||
| 114 | 140 | @Override | |
@@ -128,36 +154,27 @@ public WxCpChatModel getDecryptData(@NonNull long sdk, @NonNull WxCpChatDatas.Wx | |||
| 128 | 154 | * @throws Exception the exception | |
| 129 | 155 | */ | |
| 130 | 156 | public String decryptChatData(long sdk, WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception { | |
| 131 | - /** | ||
| 132 | - * 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。 | ||
| 133 | - * msgAuditPriKey 会话存档私钥不能为空 | ||
| 134 | - */ | ||
| 157 | + // 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。 | ||
| 158 | + // msgAuditPriKey 会话存档私钥不能为空 | ||
| 135 | 159 | String priKey = cpService.getWxCpConfigStorage().getMsgAuditPriKey(); | |
| 136 | 160 | if (StringUtils.isEmpty(priKey)) { | |
| 137 | 161 | throw new WxErrorException("请配置会话存档私钥【msgAuditPriKey】"); | |
| 138 | 162 | } | |
| 139 | 163 | ||
| 140 | 164 | String decryptByPriKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1); | |
| 141 | - /** | ||
| 142 | - * 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。 | ||
| 143 | - */ | ||
| 165 | + // 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。 | ||
| 144 | 166 | long msg = Finance.NewSlice(); | |
| 145 | 167 | ||
| 146 | - /** | ||
| 147 | - * 解密会话存档内容 | ||
| 148 | - * sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。 | ||
| 149 | - * 此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。 | ||
| 150 | - */ | ||
| 168 | + // 解密会话存档内容 | ||
| 169 | + // sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。 | ||
| 170 | + // 此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。 | ||
| 151 | 171 | int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg); | |
| 152 | 172 | if (ret != 0) { | |
| 153 | 173 | Finance.FreeSlice(msg); | |
| 154 | - Finance.DestroySdk(sdk); | ||
| 155 | 174 | throw new WxErrorException("msg err ret " + ret); | |
| 156 | 175 | } | |
| 157 | 176 | ||
| 158 | - /** | ||
| 159 | - * 明文 | ||
| 160 | - */ | ||
| 177 | + // 明文 | ||
| 161 | 178 | String plainText = Finance.GetContentFromSlice(msg); | |
| 162 | 179 | Finance.FreeSlice(msg); | |
| 163 | 180 | return plainText; | |
@@ -209,7 +226,6 @@ public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String pr | |||
| 209 | 226 | ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData); | |
| 210 | 227 | if (ret != 0) { | |
| 211 | 228 | Finance.FreeMediaData(mediaData); | |
| 212 | - Finance.DestroySdk(sdk); | ||
| 213 | 229 | throw new WxErrorException("getmediadata err ret " + ret); | |
| 214 | 230 | } | |
| 215 | 231 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -260,7 +260,36 @@ public interface WxCpConfigStorage { | |||
| 260 | 260 | ||
| 261 | 261 | /** | |
| 262 | 262 | * 获取会话存档的secret | |
| 263 | + * | ||
| 263 | 264 | * @return msg audit secret | |
| 264 | 265 | */ | |
| 265 | 266 | String getMsgAuditSecret(); | |
| 267 | + | ||
| 268 | + /** | ||
| 269 | + * 获取会话存档SDK | ||
| 270 | + * 会话存档SDK初始化后有效期为7200秒,无需每次重新初始化 | ||
| 271 | + * | ||
| 272 | + * @return sdk id,如果未初始化或已过期返回0 | ||
| 273 | + */ | ||
| 274 | + long getMsgAuditSdk(); | ||
| 275 | + | ||
| 276 | + /** | ||
| 277 | + * 检查会话存档SDK是否已过期 | ||
| 278 | + * | ||
| 279 | + * @return true: 已过期, false: 未过期 | ||
| 280 | + */ | ||
| 281 | + boolean isMsgAuditSdkExpired(); | ||
| 282 | + | ||
| 283 | + /** | ||
| 284 | + * 更新会话存档SDK | ||
| 285 | + * | ||
| 286 | + * @param sdk sdk id | ||
| 287 | + * @param expiresInSeconds 过期时间(秒) | ||
| 288 | + */ | ||
| 289 | + void updateMsgAuditSdk(long sdk, int expiresInSeconds); | ||
| 290 | + | ||
| 291 | + /** | ||
| 292 | + * 使会话存档SDK过期 | ||
| 293 | + */ | ||
| 294 | + void expireMsgAuditSdk(); | ||
| 266 | 295 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -49,6 +49,11 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable { | |||
| 49 | 49 | private volatile String msgAuditSecret; | |
| 50 | 50 | private volatile String msgAuditPriKey; | |
| 51 | 51 | private volatile String msgAuditLibPath; | |
| 52 | + /** | ||
| 53 | + * 会话存档SDK及其过期时间 | ||
| 54 | + */ | ||
| 55 | + private volatile long msgAuditSdk; | ||
| 56 | + private volatile long msgAuditSdkExpiresTime; | ||
| 52 | 57 | private volatile String oauth2redirectUri; | |
| 53 | 58 | private volatile String httpProxyHost; | |
| 54 | 59 | private volatile int httpProxyPort; | |
@@ -444,10 +449,34 @@ public String getMsgAuditSecret() { | |||
| 444 | 449 | ||
| 445 | 450 | /** | |
| 446 | 451 | * 设置会话存档secret | |
| 447 | - * @param msgAuditSecret | ||
| 452 | + * | ||
| 453 | + * @param msgAuditSecret the msg audit secret | ||
| 454 | + * @return this | ||
| 448 | 455 | */ | |
| 449 | 456 | public WxCpDefaultConfigImpl setMsgAuditSecret(String msgAuditSecret) { | |
| 450 | 457 | this.msgAuditSecret = msgAuditSecret; | |
| 451 | 458 | return this; | |
| 452 | 459 | } | |
| 460 | + | ||
| 461 | + @Override | ||
| 462 | + public long getMsgAuditSdk() { | ||
| 463 | + return this.msgAuditSdk; | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + @Override | ||
| 467 | + public boolean isMsgAuditSdkExpired() { | ||
| 468 | + return System.currentTimeMillis() > this.msgAuditSdkExpiresTime; | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + @Override | ||
| 472 | + public synchronized void updateMsgAuditSdk(long sdk, int expiresInSeconds) { | ||
| 473 | + this.msgAuditSdk = sdk; | ||
| 474 | + // 预留200秒的时间 | ||
| 475 | + this.msgAuditSdkExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | ||
| 476 | + } | ||
| 477 | + | ||
| 478 | + @Override | ||
| 479 | + public void expireMsgAuditSdk() { | ||
| 480 | + this.msgAuditSdkExpiresTime = 0; | ||
| 481 | + } | ||
| 453 | 482 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -50,6 +50,11 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage { | |||
| 50 | 50 | private volatile File tmpDirFile; | |
| 51 | 51 | private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; | |
| 52 | 52 | private volatile String webhookKey; | |
| 53 | + /** | ||
| 54 | + * 会话存档SDK及其过期时间(SDK是本地JVM变量,不适合存储到Redis) | ||
| 55 | + */ | ||
| 56 | + private volatile long msgAuditSdk; | ||
| 57 | + private volatile long msgAuditSdkExpiresTime; | ||
| 53 | 58 | ||
| 54 | 59 | /** | |
| 55 | 60 | * Instantiates a new Wx cp redis config. | |
@@ -470,4 +475,26 @@ public String getWebhookKey() { | |||
| 470 | 475 | public String getMsgAuditSecret() { | |
| 471 | 476 | return null; | |
| 472 | 477 | } | |
| 478 | + | ||
| 479 | + @Override | ||
| 480 | + public long getMsgAuditSdk() { | ||
| 481 | + return this.msgAuditSdk; | ||
| 482 | + } | ||
| 483 | + | ||
| 484 | + @Override | ||
| 485 | + public boolean isMsgAuditSdkExpired() { | ||
| 486 | + return System.currentTimeMillis() > this.msgAuditSdkExpiresTime; | ||
| 487 | + } | ||
| 488 | + | ||
| 489 | + @Override | ||
| 490 | + public synchronized void updateMsgAuditSdk(long sdk, int expiresInSeconds) { | ||
| 491 | + this.msgAuditSdk = sdk; | ||
| 492 | + // 预留200秒的时间 | ||
| 493 | + this.msgAuditSdkExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + @Override | ||
| 497 | + public void expireMsgAuditSdk() { | ||
| 498 | + this.msgAuditSdkExpiresTime = 0; | ||
| 499 | + } | ||
| 473 | 500 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments