jedisPool, String keyPrefix) {
+ super(new JedisWxRedisOps(jedisPool), keyPrefix);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java
new file mode 100644
index 000000000..0a94afc79
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.cp.config.impl;
+
+import lombok.Builder;
+import lombok.NonNull;
+import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+/**
+ * 基于 RedisTemplate 的实现
+ *
+ * @author yl
+ * created on 2023/04/23
+ */
+public class WxCpTpRedisTemplateConfigImpl extends AbstractWxCpTpInRedisConfigImpl {
+ private static final long serialVersionUID = -1660004125413310620L;
+
+ public WxCpTpRedisTemplateConfigImpl(@NonNull StringRedisTemplate stringRedisTemplate) {
+ this(stringRedisTemplate, null);
+ }
+
+ public WxCpTpRedisTemplateConfigImpl(@NonNull StringRedisTemplate stringRedisTemplate, String keyPrefix) {
+ super(new RedisTemplateWxRedisOps(stringRedisTemplate), keyPrefix);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
index d483bfd53..fe8723a8a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
@@ -1,449 +1,25 @@
package me.chanjar.weixin.cp.config.impl;
-
import lombok.Builder;
+import lombok.Data;
import lombok.NonNull;
-import lombok.Setter;
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.redis.WxRedisOps;
-import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
-import me.chanjar.weixin.cp.bean.WxCpProviderToken;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
-import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.File;
-import java.io.Serializable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
+import me.chanjar.weixin.common.redis.RedissonWxRedisOps;
+import org.redisson.api.RedissonClient;
/**
- * 企业微信各种固定、授权配置的Redisson存储实现
+ * 基于Redisson的实现
+ *
+ * @author yuanqixun created on 2020 /5/13
+ * @author yl
*/
-@Builder
-public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializable {
- private static final long serialVersionUID = -5385639031981770319L;
+public class WxCpTpRedissonConfigImpl extends AbstractWxCpTpInRedisConfigImpl {
+ private static final long serialVersionUID = -5674792341070783967L;
- /**
- * The constant LOCK_KEY.
- */
-// lock key
- protected static final String LOCK_KEY = "wechat_tp_lock:";
- /**
- * The constant LOCKER_PROVIDER_ACCESS_TOKEN.
- */
- protected static final String LOCKER_PROVIDER_ACCESS_TOKEN = "providerAccessTokenLock";
- /**
- * The constant LOCKER_SUITE_ACCESS_TOKEN.
- */
- protected static final String LOCKER_SUITE_ACCESS_TOKEN = "suiteAccessTokenLock";
- /**
- * The constant LOCKER_ACCESS_TOKEN.
- */
- protected static final String LOCKER_ACCESS_TOKEN = "accessTokenLock";
- /**
- * The constant LOCKER_CORP_JSAPI_TICKET.
- */
- protected static final String LOCKER_CORP_JSAPI_TICKET = "corpJsapiTicketLock";
- /**
- * The constant LOCKER_SUITE_JSAPI_TICKET.
- */
- protected static final String LOCKER_SUITE_JSAPI_TICKET = "suiteJsapiTicketLock";
- @NonNull
- private final WxRedisOps wxRedisOps;
- private final String suiteAccessTokenKey = ":suiteAccessTokenKey:";
- private final String suiteTicketKey = ":suiteTicketKey:";
- private final String accessTokenKey = ":accessTokenKey:";
- private final String authCorpJsApiTicketKey = ":authCorpJsApiTicketKey:";
- private final String authSuiteJsApiTicketKey = ":authSuiteJsApiTicketKey:";
- private final String providerTokenKey = ":providerTokenKey:";
- /**
- * redis里面key的统一前缀
- */
- @Setter
- private String keyPrefix = "";
- private volatile String baseApiUrl;
- private volatile String httpProxyHost;
- private volatile int httpProxyPort;
- private volatile String httpProxyUsername;
- private volatile String httpProxyPassword;
- private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
- private volatile File tmpDirFile;
- /**
- * 第三方应用的其他配置,来自于企微配置
- */
- private volatile String suiteId;
- private volatile String suiteSecret;
- /**
- * 第三方应用的token,用来检查应用的签名
- */
- private volatile String token;
- /**
- * 第三方应用的EncodingAESKey,用来检查签名
- */
- private volatile String aesKey;
- /**
- * 企微服务商企业ID & 企业secret,来自于企微配置
- */
- private volatile String corpId;
- private volatile String corpSecret;
- /**
- * 服务商secret
- */
- private volatile String providerSecret;
-
- @Override
- public void setBaseApiUrl(String baseUrl) {
- this.baseApiUrl = baseUrl;
+ public WxCpTpRedissonConfigImpl(@NonNull RedissonClient redissonClient) {
+ this(redissonClient, null);
}
- @Override
- public String getApiUrl(String path) {
- if (baseApiUrl == null) {
- baseApiUrl = "https://qyapi.weixin.qq.com";
- }
- return baseApiUrl + path;
- }
-
-
- /**
- * 第三方应用的suite access token相关
- */
- @Override
- public String getSuiteAccessToken() {
- return wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
- }
-
- @Override
- public WxAccessToken getSuiteAccessTokenEntity() {
- String suiteAccessToken = wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
- Long expireIn = wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey));
- if (StringUtils.isBlank(suiteAccessToken) || expireIn == null || expireIn == 0 || expireIn == -2) {
- return new WxAccessToken();
- }
-
- WxAccessToken suiteAccessTokenEntity = new WxAccessToken();
- suiteAccessTokenEntity.setAccessToken(suiteAccessToken);
- suiteAccessTokenEntity.setExpiresIn(Math.max(Math.toIntExact(expireIn), 0));
- return suiteAccessTokenEntity;
- }
-
- @Override
- public boolean isSuiteAccessTokenExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == -2;
- }
-
- @Override
- public void expireSuiteAccessToken() {
- wxRedisOps.expire(keyWithPrefix(suiteAccessTokenKey), 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateSuiteAccessToken(WxAccessToken suiteAccessToken) {
- updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn());
- }
-
- @Override
- public void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(suiteAccessTokenKey), suiteAccessToken, expiresInSeconds, TimeUnit.SECONDS);
- }
-
- /**
- * 第三方应用的suite ticket相关
- */
- @Override
- public String getSuiteTicket() {
- return wxRedisOps.getValue(keyWithPrefix(suiteTicketKey));
- }
-
- @Override
- public boolean isSuiteTicketExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == -2;
- }
-
- @Override
- public void expireSuiteTicket() {
- wxRedisOps.expire(keyWithPrefix(suiteTicketKey), 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateSuiteTicket(String suiteTicket, int expiresInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(suiteTicketKey), suiteTicket, expiresInSeconds, TimeUnit.SECONDS);
- }
-
- /**
- * 第三方应用的其他配置,来自于企微配置
- */
- @Override
- public String getSuiteId() {
- return suiteId;
- }
-
- @Override
- public String getSuiteSecret() {
- return suiteSecret;
- }
-
- // 第三方应用的token,用来检查应用的签名
- @Override
- public String getToken() {
- return token;
- }
-
- //第三方应用的EncodingAESKey,用来检查签名
- @Override
- public String getAesKey() {
- return aesKey;
- }
-
-
- /**
- * 企微服务商企业ID & 企业secret, 来自于企微配置
- */
- @Override
- public String getCorpId() {
- return corpId;
- }
-
- @Override
- public String getCorpSecret() {
- return corpSecret;
- }
-
- @Override
- public void setProviderSecret(String providerSecret) {
- this.providerSecret = providerSecret;
- }
-
- @Override
- public String getProviderSecret() {
- return providerSecret;
- }
-
- /**
- * 授权企业的access token相关
- */
- @Override
- public String getAccessToken(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
- }
-
- @Override
- public WxAccessToken getAccessTokenEntity(String authCorpId) {
- String accessToken = wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
- Long expire = wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey);
- if (StringUtils.isBlank(accessToken) || expire == null || expire == 0 || expire == -2) {
- return new WxAccessToken();
- }
-
- WxAccessToken accessTokenEntity = new WxAccessToken();
- accessTokenEntity.setAccessToken(accessToken);
- accessTokenEntity.setExpiresIn((int) ((expire - System.currentTimeMillis()) / 1000 + 200));
- return accessTokenEntity;
- }
-
- @Override
- public boolean isAccessTokenExpired(String authCorpId) {
- //没有设置或者TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == -2;
- }
-
- @Override
- public void expireAccessToken(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + accessTokenKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAccessToken(String authCorpId, String accessToken, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + accessTokenKey, accessToken, expiredInSeconds, TimeUnit.SECONDS);
- }
-
-
- /**
- * 授权企业的js api ticket相关
- */
- @Override
- public String getAuthCorpJsApiTicket(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey);
- }
-
- @Override
- public boolean isAuthCorpJsApiTicketExpired(String authCorpId) {
- //没有设置或TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == -2;
- }
-
- @Override
- public void expireAuthCorpJsApiTicket(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, jsApiTicket, expiredInSeconds,
- TimeUnit.SECONDS);
- }
-
-
- /**
- * 授权企业的第三方应用js api ticket相关
- */
- @Override
- public String getAuthSuiteJsApiTicket(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey);
- }
-
- @Override
- public boolean isAuthSuiteJsApiTicketExpired(String authCorpId) {
- //没有设置或者TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == -2;
- }
-
- @Override
- public void expireAuthSuiteJsApiTicket(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds,
- TimeUnit.SECONDS);
- }
-
- @Override
- public boolean isProviderTokenExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == 0L || wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == -2;
- }
-
- @Override
- public void updateProviderToken(String providerToken, int expiredInSeconds) {
- wxRedisOps.setValue(providerKeyWithPrefix(providerTokenKey), providerToken, expiredInSeconds, TimeUnit.SECONDS);
- }
-
- @Override
- public String getProviderToken() {
- return wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
- }
-
- @Override
- public WxCpProviderToken getProviderTokenEntity() {
- String providerToken = wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
- Long expire = wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey));
-
- if (StringUtils.isBlank(providerToken) || expire == null || expire == 0 || expire == -2) {
- return new WxCpProviderToken();
- }
-
- WxCpProviderToken wxCpProviderToken = new WxCpProviderToken();
- wxCpProviderToken.setProviderAccessToken(providerToken);
- wxCpProviderToken.setExpiresIn(Math.max(Math.toIntExact(expire), 0));
- return wxCpProviderToken;
- }
-
- @Override
- public void expireProviderToken() {
- wxRedisOps.expire(providerKeyWithPrefix(providerTokenKey), 0, TimeUnit.SECONDS);
- }
-
- /**
- * 网络代理相关
- */
- @Override
- public String getHttpProxyHost() {
- return this.httpProxyHost;
- }
-
- @Override
- public int getHttpProxyPort() {
- return this.httpProxyPort;
- }
-
- @Override
- public String getHttpProxyUsername() {
- return this.httpProxyUsername;
- }
-
- @Override
- public String getHttpProxyPassword() {
- return this.httpProxyPassword;
- }
-
- @Override
- public File getTmpDirFile() {
- return tmpDirFile;
- }
-
- @Override
- public Lock getProviderAccessTokenLock() {
- return getProviderLockByKey(String.join(":", this.corpId, LOCKER_PROVIDER_ACCESS_TOKEN));
- }
-
- @Override
- public Lock getSuiteAccessTokenLock() {
- return getLockByKey(LOCKER_SUITE_ACCESS_TOKEN);
- }
-
- @Override
- public Lock getAccessTokenLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_ACCESS_TOKEN));
- }
-
- @Override
- public Lock getAuthCorpJsapiTicketLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_CORP_JSAPI_TICKET));
- }
-
- @Override
- public Lock getSuiteJsapiTicketLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_SUITE_JSAPI_TICKET));
- }
-
- private Lock getLockByKey(String key) {
- // 最终key的模式:(keyPrefix:)wechat_tp_lock:suiteId:(authCorpId):lockKey
- // 其中keyPrefix目前不支持外部配置,authCorpId只有涉及到corpAccessToken, suiteJsapiTicket, authCorpJsapiTicket时才会拼上
- return this.wxRedisOps.getLock(String.join(":", keyWithPrefix(LOCK_KEY + this.suiteId), key));
- }
-
- /**
- * 单独处理provider,且不应和suite 有关系
- */
- private Lock getProviderLockByKey(String key) {
- return this.wxRedisOps.getLock(String.join(":", providerKeyWithPrefix(LOCK_KEY), key));
- }
-
- @Override
- public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
- return this.apacheHttpClientBuilder;
- }
-
- @Override
- public boolean autoRefreshToken() {
- return false;
- }
-
- @Override
- public String toString() {
- return WxCpGsonBuilder.create().toJson(this);
- }
-
- /**
- * 一个provider 会有多个suite,需要唯一标识作为前缀
- */
- private String keyWithPrefix(String key) {
- return keyPrefix + ":" + suiteId + ":" + key;
- }
-
- /**
- * provider 应该独享一个key,且不和任何suite关联
- * 一个provider 会有多个suite,不同的suite 都应该指向同一个provider 的数据
- */
- private String providerKeyWithPrefix(String key) {
- return keyPrefix + ":" + corpId + ":" + key;
+ public WxCpTpRedissonConfigImpl(@NonNull RedissonClient redissonClient, String keyPrefix) {
+ super(new RedissonWxRedisOps(redissonClient), keyPrefix);
}
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index 093d386e6..fb6f8ef68 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -855,6 +855,10 @@ public interface WxCpApiPathConsts {
* The constant GET_PERMANENT_CODE.
*/
String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code";
+ /**
+ * The constant GET_V2_PERMANENT_CODE.
+ */
+ String GET_V2_PERMANENT_CODE = "/cgi-bin/service/v2/get_permanent_code";
/**
* The constant GET_SUITE_TOKEN.
*/
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
index 5c433c0b4..b24be535d 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
@@ -8,6 +8,7 @@ import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.cp.bean.*;
+import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import java.util.List;
@@ -186,6 +187,8 @@ public interface WxCpTpService {
@Deprecated
WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException;
+ WxCpTpCorp getV2PermanentCode(String authCode) throws WxErrorException;
+
/**
* 获取企业永久授权码信息
*
@@ -200,6 +203,8 @@ public interface WxCpTpService {
*/
WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException;
+ WxCpTpPermanentCodeInfo getV2PermanentCodeInfo(String authCode) throws WxErrorException;
+
/**
*
* 获取预授权链接
@@ -343,9 +348,7 @@ public interface WxCpTpService {
* 获取WxCpTpConfigStorage 对象.
*
* @return WxCpTpConfigStorage wx cp tp config storage
- * @deprecated storage应该在service内部使用 ,提供这个接口,容易破坏这个封装
*/
- @Deprecated
WxCpTpConfigStorage getWxCpTpConfigStorage();
/**
@@ -527,6 +530,11 @@ public interface WxCpTpService {
*/
WxCpTpLicenseService getWxCpTpLicenseService();
+ WxCpTpXmlMessage fromEncryptedXml(String encryptedXml,
+ String timestamp, String nonce, String msgSignature);
+
+ String getVerifyDecrypt(String sVerifyEchoStr);
+
/**
* 获取应用的管理员列表
*
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
index 9d620264c..f8f554b81 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
@@ -25,8 +25,10 @@ import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.cp.bean.*;
+import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.tp.service.*;
+import me.chanjar.weixin.cp.util.crypto.WxCpTpCryptUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@@ -91,6 +93,7 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
private final WxSessionManager sessionManager = new StandardSessionManager();
+
/**
* 临时文件目录.
*/
@@ -259,6 +262,18 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
return wxCpTpCorp;
}
+ @Override
+ public WxCpTpCorp getV2PermanentCode(String authCode) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("auth_code", authCode);
+
+ String result = post(configStorage.getApiUrl(GET_V2_PERMANENT_CODE), jsonObject.toString());
+ jsonObject = GsonParser.parse(result);
+ WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsJsonObject().toString());
+ wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString());
+ return wxCpTpCorp;
+ }
+
@Override
public WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
@@ -267,6 +282,14 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
return WxCpTpPermanentCodeInfo.fromJson(result);
}
+ @Override
+ public WxCpTpPermanentCodeInfo getV2PermanentCodeInfo(String authCode) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("auth_code", authCode);
+ String result = post(configStorage.getApiUrl(GET_V2_PERMANENT_CODE), jsonObject.toString());
+ return WxCpTpPermanentCodeInfo.fromJson(result);
+ }
+
@Override
@SneakyThrows
public String getPreAuthUrl(String redirectUri, String state) throws WxErrorException {
@@ -452,7 +475,7 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
if (error.getErrorCode() == WxCpErrorMsgEnum.CODE_42009.getCode()) {
// 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token
this.configStorage.expireSuiteAccessToken();
- if (this.getWxCpTpConfigStorage().autoRefreshToken()) {
+ if (this.configStorage.autoRefreshToken()) {
log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
@@ -646,6 +669,27 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
this.wxCpTpUserService = wxCpTpUserService;
}
+
+ /**
+ *
+ * @param encryptedXml the encrypted xml
+ * @param timestamp the timestamp
+ * @param nonce the nonce
+ * @param msgSignature the msg signature
+ * @return the wx cp tp xml message
+ */
+ @Override
+ public WxCpTpXmlMessage fromEncryptedXml(String encryptedXml,
+ String timestamp, String nonce, String msgSignature) {
+ return WxCpTpXmlMessage.fromEncryptedXml(encryptedXml,this.configStorage,timestamp,nonce,msgSignature);
+ }
+
+ @Override
+ public String getVerifyDecrypt(String sVerifyEchoStr) {
+ WxCpTpCryptUtil cryptUtil = new WxCpTpCryptUtil(this.configStorage);
+ return cryptUtil.decrypt(sVerifyEchoStr);
+ }
+
@Override
public WxCpTpAdmin getAdminList(String authCorpId, Integer agentId) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
@@ -764,4 +808,9 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
public void setWxCpTpOAuth2Service(WxCpTpOAuth2Service wxCpTpOAuth2Service) {
this.wxCpTpOAuth2Service = wxCpTpOAuth2Service;
}
+
+ @Override
+ public WxCpTpConfigStorage getWxCpTpConfigStorage() {
+ return this.configStorage;
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
index a5948a99c..a28751333 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
@@ -101,9 +101,9 @@ public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl {
+ private HttpConnectionProvider httpClient;
+ private ProxyInfo httpProxy;
+
+ @Override
+ public HttpConnectionProvider getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public ProxyInfo getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.JODD_HTTP;
+ }
+
+ @Override
+ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ synchronized (this.globalSuiteAccessTokenRefreshLock) {
+ // 构建请求 URL
+ String url = this.configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN);
+
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+ jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+ jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+ String jsonBody = jsonObject.toString();
+
+ if (this.httpProxy != null) {
+ httpClient.useProxy(this.httpProxy);
+ }
+ // 创建 POST 请求
+ HttpRequest request = HttpRequest
+ .post(url)
+ .contentType("application/json")
+ .body(jsonBody); // 使用 .body() 设置请求体
+
+ request.withConnectionProvider(httpClient);
+
+ // 发送请求
+ HttpResponse response = request.send();
+
+ // 解析响应
+ String resultContent = response.bodyText();
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+
+ // 更新 access token
+ jsonObject = GsonParser.parse(resultContent);
+ String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
+ this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+ }
+
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+ httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(),
+ configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword());
+ }
+
+ httpClient = new SocketHttpConnectionProvider();
+ }
+//
+// @Override
+// public WxCpConfigStorage getWxCpConfigStorage() {
+// return this.configStorage;
+// }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java
new file mode 100644
index 000000000..63d5e95ba
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java
@@ -0,0 +1,130 @@
+package me.chanjar.weixin.cp.tp.service.impl;
+
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+import okhttp3.*;
+
+import java.io.IOException;
+
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_TOKEN;
+
+/**
+ * The type Wx cp service ok http.
+ *
+ * @author someone
+ */
+@Slf4j
+public class WxCpTpServiceOkHttpImpl extends BaseWxCpTpServiceImpl {
+ private OkHttpClient httpClient;
+ private OkHttpProxyInfo httpProxy;
+
+ @Override
+ public OkHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public OkHttpProxyInfo getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.OK_HTTP;
+ }
+
+ @Override
+ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ synchronized (this.globalSuiteAccessTokenRefreshLock) {
+ // 得到 httpClient
+ OkHttpClient client = getRequestHttpClient();
+
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+ jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+ jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+ String jsonBody = jsonObject.toString();
+
+ RequestBody requestBody = RequestBody.create(
+ MediaType.get("application/json; charset=utf-8"),
+ jsonBody
+ );
+
+ // 构建 POST 请求
+ Request request = new Request.Builder()
+ .url(this.configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN)) // URL 不包含查询参数
+ .post(requestBody) // 使用 POST 方法
+ .build();
+
+ String resultContent = null;
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ throw new IOException("Unexpected response code: " + response);
+ }
+ resultContent = response.body().string();
+ } catch (IOException e) {
+ log.error("获取 suite token 失败: {}", e.getMessage(), e);
+ throw new WxRuntimeException("获取 suite token 失败", e);
+ }
+
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+
+ jsonObject = GsonParser.parse(resultContent);
+ String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
+ this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+ }
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ log.debug("WxCpServiceOkHttpImpl initHttp");
+ //设置代理
+ if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+ httpProxy = OkHttpProxyInfo.httpProxy(configStorage.getHttpProxyHost(),
+ configStorage.getHttpProxyPort(),
+ configStorage.getHttpProxyUsername(),
+ configStorage.getHttpProxyPassword());
+ OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
+ clientBuilder.proxy(getRequestHttpProxy().getProxy());
+ //设置授权
+ clientBuilder.authenticator(new Authenticator() {
+ @Override
+ public Request authenticate(Route route, Response response) throws IOException {
+ String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
+ return response.request().newBuilder()
+ .header("Authorization", credential)
+ .build();
+ }
+ });
+ httpClient = clientBuilder.build();
+ } else {
+ httpClient = DefaultOkHttpClientBuilder.get().build();
+ }
+ }
+
+// @Override
+// public WxCpConfigStorage getWxCpConfigStorage() {
+// return this.configStorage;
+// }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
index ac6097446..4e9783e3e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
@@ -23,7 +23,7 @@ public class WxCpTpCryptUtil extends WxCryptUtil {
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
* @param appidOrCorpid 公众平台corpId
*/
- String encodingAesKey = wxCpTpConfigStorage.getAesKey();
+ String encodingAesKey = wxCpTpConfigStorage.getEncodingAESKey();
String token = wxCpTpConfigStorage.getToken();
String corpId = wxCpTpConfigStorage.getCorpId();
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
index 6f2639c89..c0fc2d614 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
@@ -9,6 +9,8 @@ import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo;
import me.chanjar.weixin.cp.bean.WxTpCustomizedAuthUrl;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
+import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
+import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import org.mockito.Mockito;
@@ -69,7 +71,10 @@ public class BaseWxCpTpServiceImplTest {
* @return the wx cp tp config storage
*/
public WxCpTpConfigStorage wxCpTpConfigStorage() {
- return WxCpTpRedissonConfigImpl.builder().corpId(PROVIDER_CORP_ID).providerSecret(PROVIDER_SECRET).wxRedisOps(new RedissonWxRedisOps(redissonClient())).build();
+ WxCpTpRedissonConfigImpl wxCpTpRedissonConfig=new WxCpTpRedissonConfigImpl(redissonClient(),"");
+ wxCpTpRedissonConfig.setCorpId(PROVIDER_CORP_ID);
+ wxCpTpRedissonConfig.setProviderSecret(PROVIDER_SECRET);
+ return wxCpTpRedissonConfig;
}
/**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
index 75927af4d..b46ddf003 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
@@ -6,6 +6,8 @@ import me.chanjar.weixin.common.redis.RedissonWxRedisOps;
import me.chanjar.weixin.cp.bean.WxCpProviderToken;
import me.chanjar.weixin.cp.bean.WxCpTpCorpId2OpenCorpId;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
+import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import org.apache.commons.lang3.StringUtils;
@@ -48,14 +50,10 @@ public class WxCpTpServiceApacheHttpClientImplTest {
* The constant PROVIDER_CORP_ID.
*/
public static final String PROVIDER_CORP_ID = "xxxxxx";
- /**
- * The constant CORP_SECRET.
- */
- public static final String CORP_SECRET = "xxxxxx";
/**
* The constant PROVIDER_SECRET.
*/
- public static final String PROVIDER_SECRET = CORP_SECRET;
+ public static final String PROVIDER_SECRET = "xxxxxx";
/**
* The constant REDIS_ADDR.
*/
@@ -85,9 +83,15 @@ public class WxCpTpServiceApacheHttpClientImplTest {
* @return the wx cp tp config storage
*/
public WxCpTpConfigStorage wxCpTpConfigStorage() {
- return WxCpTpRedissonConfigImpl.builder().baseApiUrl(API_URL).suiteId(SUITE_ID).suiteSecret(SUITE_SECRET)
- .token(TOKEN).aesKey(AES_KEY).corpId(PROVIDER_CORP_ID).corpSecret(CORP_SECRET).providerSecret(PROVIDER_SECRET)
- .wxRedisOps(new RedissonWxRedisOps(redissonClient())).build();
+ WxCpTpRedissonConfigImpl wxCpTpRedissonConfig=new WxCpTpRedissonConfigImpl(redissonClient(),"");
+ wxCpTpRedissonConfig.setBaseApiUrl(API_URL);
+ wxCpTpRedissonConfig.setSuiteId(SUITE_ID);
+ wxCpTpRedissonConfig.setSuiteSecret(SUITE_SECRET);
+ wxCpTpRedissonConfig.setToken(TOKEN);
+ wxCpTpRedissonConfig.setEncodingAESKey(AES_KEY);
+ wxCpTpRedissonConfig.setCorpId(PROVIDER_CORP_ID);
+ wxCpTpRedissonConfig.setProviderSecret(PROVIDER_SECRET);
+ return wxCpTpRedissonConfig;
}
/**