微信官方要求通讯录同步相关 API(成员/部门 CRUD)仅支持通过「通讯录同步 secret」获取的独立 access token 调用,现有实现未支持此场景#4047
微信官方要求通讯录同步相关 API(成员/部门 CRUD)仅支持通过「通讯录同步 secret」获取的独立 access token 调用,现有实现未支持此场景#4047Copilot wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
本 PR 为企业微信「通讯录同步」相关接口补齐“独立 secret + 独立 access token”的调用通道,避免通讯录成员/部门 CRUD 继续误用应用级 access token,从而满足微信官方对通讯录同步 API 的鉴权要求。
Changes:
- 扩展
WxCpConfigStorage/WxCpDefaultConfigImpl:新增并实现通讯录同步 secret、token、过期与锁相关接口。 - 扩展
WxCpService/BaseWxCpServiceImpl:新增getContactAccessToken以及getForContact/postForContact调用入口。 - 在多种 HTTP 客户端实现中增加通讯录同步 token 的获取与缓存刷新逻辑,并补充相应单测桩代码与新增测试类。
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpServiceGetMsgAuditAccessTokenTest.java | 为适配新增接口补充测试桩 getContactAccessToken 实现 |
| weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpServiceGetContactAccessTokenTest.java | 新增通讯录同步 token 缓存/刷新/锁/缺少 secret 的测试用例 |
| weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java | 为适配新增接口补充测试桩 getContactAccessToken 实现 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java | 配置存储接口新增通讯录同步 secret/token/锁/过期/更新方法 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java | 补充通讯录同步相关接口的占位实现 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java | 增加通讯录同步 secret/token/过期时间/锁字段及实现与 fluent setter |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java | WxCpService 新增通讯录同步 token 获取及基于该 token 的 GET/POST 方法声明 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java | OkHttp 客户端实现通讯录同步 token 获取与缓存刷新 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java | JoddHttp 客户端实现通讯录同步 token 获取与缓存刷新 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java | 默认 Apache HttpClient 实现补齐通讯录同步 token 获取逻辑 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java | HttpComponents 客户端实现通讯录同步 token 获取与缓存刷新 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java | Apache HttpClient 客户端实现通讯录同步 token 获取与缓存刷新 |
| weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java | 增加 getForContact / postForContact,使用通讯录同步 token 直连请求执行器 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0a9e488b78
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| @Override | ||
| public String getForContact(String url, String queryParam) throws WxErrorException { |
There was a problem hiding this comment.
当前只新增了 getForContact/postForContact,但我检查到主代码里没有任何调用点(rg "postForContact|getForContact" weixin-java-cp/src/main/java 只命中这里和接口声明);现有通讯录 CRUD 仍在 WxCpUserServiceImpl#create/update/delete 和 WxCpDepartmentServiceImpl#create/get/update/delete 中调用 mainService.post/get,因此用户即使配置了 contactSecret,通过既有的成员/部门服务调用时仍会带普通应用 secret 换来的 access_token,微信要求通讯录同步 secret 的接口仍会失败。
Useful? React with 👍 / 👎.
| public String getContactSecret() { | ||
| return null; | ||
| } |
| // 拼接access_token参数 | ||
| String urlWithToken = url + (url.contains("?") ? "&" : "?") + "access_token=" + contactAccessToken; | ||
| // 使用executeNormal方法,不自动添加token | ||
| return this.executeNormal(SimplePostRequestExecutor.create(this), urlWithToken, postData); |
There was a problem hiding this comment.
| * | ||
| * @return contact secret | ||
| */ | ||
| String getContactSecret(); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@codex[agent] 根据最新代码提交再次给出新的review,必要时直接提交修改 |
Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
已按最新提交复核:发现 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57a9da70b5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| * @return the string | ||
| * @throws WxErrorException the wx error exception | ||
| */ | ||
| String getForContact(String url, String queryParam) throws WxErrorException; |
There was a problem hiding this comment.
这里新增了通讯录专用请求入口,但我用 rg "getForContact|postForContact" 检查到它们只在接口和 Base 实现中出现,现有 WxCpUserServiceImpl 和 WxCpDepartmentServiceImpl 仍然调用 mainService.get/post(例如成员 create/list、部门 create/list)。因此用户按现有高层 API 调用成员/部门 CRUD 时,即使配置了 contactSecret,请求仍会带普通应用 access_token,在企业微信要求通讯录同步 secret 的环境下会继续失败;需要把这些通讯录相关服务切到 getForContact/postForContact。
Useful? React with 👍 / 👎.
| urlWithToken = urlWithToken + "&" + queryParam; | ||
| } | ||
| // 使用executeNormal方法,不自动添加token | ||
| return this.executeNormal(SimpleGetRequestExecutor.create(this), urlWithToken, null); |
There was a problem hiding this comment.
当微信端提前判定缓存的通讯录 access_token 无效(例如 secret 重置、token 被服务端回收或返回 40014/42001 等)时,这条路径走 executeNormal,只会把错误直接抛出,不会像普通 executeInternal 那样 expireAccessToken 后刷新并重试。结果是在本地过期时间到达前,所有 getForContact/postForContact 调用都会持续失败,除非调用方手动清理缓存;通讯录专用 token 也需要在 access-token 错误码下过期并重取。
Useful? React with 👍 / 👎.
| * | ||
| * @return contact secret | ||
| */ | ||
| String getContactSecret(); |
| public String getContactSecret() { | ||
| return null; |
There was a problem hiding this comment.
微信官方要求通讯录同步相关 API(成员/部门 CRUD)仅支持通过「通讯录同步 secret」获取的独立 access token 调用,现有实现未支持此场景。
核心变更
WxCpConfigStorage:新增getContactSecret()、getContactAccessToken()、getContactAccessTokenLock()、isContactAccessTokenExpired()、expireContactAccessToken()、updateContactAccessToken()6 个接口方法WxCpDefaultConfigImpl:新增contactSecret/contactAccessToken/过期时间/锁字段,实现上述接口方法,提供 fluent settersetContactSecret()WxCpRedisConfigImpl:补充实现新接口方法(与msgAudit保持一致,不持久化到 Redis)WxCpService:新增getContactAccessToken(boolean forceRefresh)、getForContact(url, param)、postForContact(url, data)方法声明BaseWxCpServiceImpl:实现getForContact/postForContact,自动拼接通讯录 token 并通过executeNormal绕过常规 token 注入WxCpServiceImpl):各自实现getContactAccessToken,含缓存、双重检查锁、自动刷新逻辑整体设计与已有的
msgAuditSecret模式完全对齐。用法示例