Conversation
- 添加 WxMaFaceService 接口,包含 getVerifyId 和 queryVerifyInfo 方法 - 添加 WxMaFaceServiceImpl 实现,包含 cert_hash 计算工具方法 - 添加请求/响应 bean:WxMaFaceGetVerifyIdRequest/Response、WxMaFaceQueryVerifyInfoRequest/Response - 在 WxMaApiUrlConstants 中新增 Face 接口 URL 常量 - 在 WxMaService 和 BaseWxMaServiceImpl 中注册人脸核身服务 - 新增测试类 WxMaFaceServiceImplTest(含 cert_hash 单元测试) Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
🤖 Augment PR Summary总结:本 PR 按照微信官方文档新增「小程序人脸核身」后台能力,补齐获取核身会话与查询核身结果两类接口。 主要变更:
技术说明:接口调用由底层执行器统一追加 🤖 Was this summary useful? React with 👍 or 👎 |
| byte[] hashBytes = digest.digest(raw.getBytes(StandardCharsets.UTF_8)); | ||
| StringBuilder hex = new StringBuilder(); | ||
| for (byte b : hashBytes) { | ||
| hex.append(String.format("%02x", b)); |
| .certName("张三") | ||
| .certNo("310101199801011234") | ||
| .build()) | ||
| .openid("test_openid_001") |
There was a problem hiding this comment.
testGetVerifyId/testQueryVerifyInfo 里使用了明显的占位 openid/verifyId(如 test_openid_001、test_verify_id_001),在真实调用微信接口时大概率直接报错抛 WxErrorException,会让用例不可用/不稳定。
Severity: medium
Other Locations
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaFaceServiceImplTest.java:53weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaFaceServiceImplTest.java:56
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Pull request overview
该 PR 在 weixin-java-miniapp 模块中新增“小程序人脸核身服务”后台接口封装,补齐官方文档中的 getVerifyId 与 queryVerifyInfo 两个能力,并将其纳入 WxMaService 的子服务体系,方便 SDK 使用方以统一方式调用。
Changes:
- 新增人脸核身服务接口
WxMaFaceService及实现WxMaFaceServiceImpl,封装getVerifyId/queryVerifyInfo请求。 - 新增对应的请求/响应 Bean,并补充
WxMaApiUrlConstants.Face接口地址常量。 - 在
WxMaService/BaseWxMaServiceImpl中注册并暴露getFaceService();新增相关测试类。
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaFaceServiceImplTest.java | 新增人脸核身服务测试用例(目前包含直连真实接口的用例)。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java | 增加 Face 接口 URL 常量定义。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/face/WxMaFaceQueryVerifyInfoResponse.java | 新增 queryVerifyInfo 响应模型与反序列化方法。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/face/WxMaFaceQueryVerifyInfoRequest.java | 新增 queryVerifyInfo 请求模型与序列化方法。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/face/WxMaFaceGetVerifyIdResponse.java | 新增 getVerifyId 响应模型与反序列化方法。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/face/WxMaFaceGetVerifyIdRequest.java | 新增 getVerifyId 请求模型(含 cert_info)与序列化方法。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaFaceServiceImpl.java | 新增服务实现与 cert_hash 计算工具方法。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java | 注册 WxMaFaceService 实例并提供 getter。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java | 新增 getFaceService() 对外声明。 |
| weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaFaceService.java | 新增人脸核身服务接口定义与方法注释。 |
| /** | ||
| * 计算证件信息摘要(cert_hash) | ||
| * <p> | ||
| * 计算规则: | ||
| * 1. 对 cert_type、cert_name、cert_no 字段内容进行标准 base64 编码(若含中文等Unicode字符,先进行UTF-8编码) | ||
| * 2. 按顺序拼接各个字段:cert_type=xxx&cert_name=xxx&cert_no=xxx | ||
| * 3. 对拼接串进行 SHA256 并输出十六进制小写结果 | ||
| * </p> | ||
| * | ||
| * @param certType 证件类型 | ||
| * @param certName 证件姓名 | ||
| * @param certNo 证件号码 | ||
| * @return cert_hash 十六进制小写字符串 | ||
| */ | ||
| public static String calcCertHash(String certType, String certName, String certNo) { | ||
| String encodedType = Base64.getEncoder().encodeToString(certType.getBytes(StandardCharsets.UTF_8)); | ||
| String encodedName = Base64.getEncoder().encodeToString(certName.getBytes(StandardCharsets.UTF_8)); | ||
| String encodedNo = Base64.getEncoder().encodeToString(certNo.getBytes(StandardCharsets.UTF_8)); | ||
| String raw = "cert_type=" + encodedType + "&cert_name=" + encodedName + "&cert_no=" + encodedNo; | ||
| try { | ||
| MessageDigest digest = MessageDigest.getInstance("SHA-256"); | ||
| byte[] hashBytes = digest.digest(raw.getBytes(StandardCharsets.UTF_8)); | ||
| StringBuilder hex = new StringBuilder(); | ||
| for (byte b : hashBytes) { | ||
| hex.append(String.format("%02x", b)); | ||
| } | ||
| return hex.toString(); | ||
| } catch (NoSuchAlgorithmException e) { | ||
| throw new IllegalStateException("SHA-256 algorithm not available", e); |
There was a problem hiding this comment.
calcCertHash 放在 api.impl 包下并作为 public static 暴露,会引导 SDK 使用方依赖实现类(示例/测试里也直接调用了 WxMaFaceServiceImpl.calcCertHash),不利于对外 API 的稳定性。建议将该工具方法移动到对外可见且语义更合适的位置(例如 WxMaFaceQueryVerifyInfoRequest/WxMaFaceGetVerifyIdRequest 的静态工具方法,或新增 cn.binarywang.wx.miniapp.util 下的工具类),并在实现类中改为调用新位置。
...in-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaFaceServiceImplTest.java
Outdated
Show resolved
Hide resolved
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaFaceService.java
Outdated
Show resolved
Hide resolved
| * 文档地址:<a href="https://developers.weixin.qq.com/miniprogram/dev/server/API/face/api_getverifyid">获取用户人脸核身会话唯一标识</a> | ||
| * </p> | ||
| * | ||
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> |
There was a problem hiding this comment.
Javadoc 作者信息里品牌拼写应为 “GitHub”,这里写成了 “Github”。建议统一更正为 “GitHub Copilot”。
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | |
| * @author <a href="https://github.com/github-copilot">GitHub Copilot</a> |
...va-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/face/WxMaFaceGetVerifyIdResponse.java
Outdated
Show resolved
Hide resolved
| import cn.binarywang.wx.miniapp.api.WxMaService; | ||
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceGetVerifyIdRequest; | ||
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceGetVerifyIdResponse; | ||
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceQueryVerifyInfoRequest; | ||
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceQueryVerifyInfoResponse; | ||
| import cn.binarywang.wx.miniapp.test.ApiTestModule; | ||
| import com.google.inject.Inject; | ||
| import me.chanjar.weixin.common.error.WxErrorException; | ||
| import org.testng.annotations.Guice; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.AssertJUnit.assertNotNull; | ||
|
|
||
| /** | ||
| * 微信小程序人脸核身服务测试类 | ||
| * | ||
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | ||
| */ | ||
| @Test | ||
| @Guice(modules = ApiTestModule.class) | ||
| public class WxMaFaceServiceImplTest { | ||
|
|
||
| @Inject | ||
| private WxMaService wxService; | ||
|
|
||
| @Test | ||
| public void testGetVerifyId() throws WxErrorException { | ||
| WxMaFaceGetVerifyIdRequest request = WxMaFaceGetVerifyIdRequest.builder() | ||
| .outSeqNo("TEST20240101001") | ||
| .certInfo(WxMaFaceGetVerifyIdRequest.CertInfo.builder() | ||
| .certType("IDENTITY_CARD") | ||
| .certName("张三") | ||
| .certNo("310101199801011234") | ||
| .build()) | ||
| .openid("test_openid_001") | ||
| .build(); | ||
|
|
||
| WxMaFaceGetVerifyIdResponse response = this.wxService.getFaceService().getVerifyId(request); | ||
| assertNotNull(response); | ||
| } | ||
|
|
||
| @Test | ||
| public void testQueryVerifyInfo() throws WxErrorException { | ||
| String certType = "IDENTITY_CARD"; | ||
| String certName = "张三"; | ||
| String certNo = "310101199801011234"; | ||
| String certHash = WxMaFaceServiceImpl.calcCertHash(certType, certName, certNo); | ||
|
|
||
| WxMaFaceQueryVerifyInfoRequest request = WxMaFaceQueryVerifyInfoRequest.builder() | ||
| .verifyId("test_verify_id_001") | ||
| .outSeqNo("TEST20240101001") | ||
| .certHash(certHash) | ||
| .openid("test_openid_001") | ||
| .build(); | ||
|
|
||
| WxMaFaceQueryVerifyInfoResponse response = this.wxService.getFaceService().queryVerifyInfo(request); | ||
| assertNotNull(response); | ||
| } | ||
|
|
||
| @Test |
There was a problem hiding this comment.
该测试类里的 testGetVerifyId/testQueryVerifyInfo 直接调用真实微信接口,但使用了 test_openid_001、test_verify_id_001 等占位值。由于 BaseWxMaServiceImpl.executeInternal 在 errcode != 0 时会抛 WxErrorException,这些用例在绝大多数环境下会稳定失败。建议改为用 Mockito mock WxMaService.post(...) 返回示例 JSON,只验证请求序列化/响应反序列化与方法路由;或仅保留纯本地的 calcCertHash 计算测试。
| import cn.binarywang.wx.miniapp.api.WxMaService; | |
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceGetVerifyIdRequest; | |
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceGetVerifyIdResponse; | |
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceQueryVerifyInfoRequest; | |
| import cn.binarywang.wx.miniapp.bean.face.WxMaFaceQueryVerifyInfoResponse; | |
| import cn.binarywang.wx.miniapp.test.ApiTestModule; | |
| import com.google.inject.Inject; | |
| import me.chanjar.weixin.common.error.WxErrorException; | |
| import org.testng.annotations.Guice; | |
| import org.testng.annotations.Test; | |
| import static org.testng.Assert.assertEquals; | |
| import static org.testng.AssertJUnit.assertNotNull; | |
| /** | |
| * 微信小程序人脸核身服务测试类 | |
| * | |
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | |
| */ | |
| @Test | |
| @Guice(modules = ApiTestModule.class) | |
| public class WxMaFaceServiceImplTest { | |
| @Inject | |
| private WxMaService wxService; | |
| @Test | |
| public void testGetVerifyId() throws WxErrorException { | |
| WxMaFaceGetVerifyIdRequest request = WxMaFaceGetVerifyIdRequest.builder() | |
| .outSeqNo("TEST20240101001") | |
| .certInfo(WxMaFaceGetVerifyIdRequest.CertInfo.builder() | |
| .certType("IDENTITY_CARD") | |
| .certName("张三") | |
| .certNo("310101199801011234") | |
| .build()) | |
| .openid("test_openid_001") | |
| .build(); | |
| WxMaFaceGetVerifyIdResponse response = this.wxService.getFaceService().getVerifyId(request); | |
| assertNotNull(response); | |
| } | |
| @Test | |
| public void testQueryVerifyInfo() throws WxErrorException { | |
| String certType = "IDENTITY_CARD"; | |
| String certName = "张三"; | |
| String certNo = "310101199801011234"; | |
| String certHash = WxMaFaceServiceImpl.calcCertHash(certType, certName, certNo); | |
| WxMaFaceQueryVerifyInfoRequest request = WxMaFaceQueryVerifyInfoRequest.builder() | |
| .verifyId("test_verify_id_001") | |
| .outSeqNo("TEST20240101001") | |
| .certHash(certHash) | |
| .openid("test_openid_001") | |
| .build(); | |
| WxMaFaceQueryVerifyInfoResponse response = this.wxService.getFaceService().queryVerifyInfo(request); | |
| assertNotNull(response); | |
| } | |
| @Test | |
| import org.testng.annotations.Test; | |
| import static org.testng.Assert.assertEquals; | |
| /** | |
| * 微信小程序人脸核身服务本地计算测试类 | |
| * | |
| * 仅验证证件哈希计算逻辑,避免依赖真实微信接口。 | |
| */ | |
| @Test | |
| public class WxMaFaceServiceImplTest { | |
| @Test |
| import org.testng.annotations.Test; | ||
|
|
||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.AssertJUnit.assertNotNull; |
There was a problem hiding this comment.
这里同时静态导入了 org.testng.Assert.assertEquals 和 org.testng.AssertJUnit.assertNotNull,断言库混用会降低可读性并可能引入行为差异。建议统一使用 TestNG 的 org.testng.Assert(例如静态导入 assertNotNull),与本模块其他测试类保持一致。
| import static org.testng.AssertJUnit.assertNotNull; | |
| import static org.testng.Assert.assertNotNull; |
| /** | ||
| * 微信小程序人脸核身相关接口实现 | ||
| * | ||
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> |
There was a problem hiding this comment.
Javadoc 作者信息里品牌拼写应为 “GitHub”,这里写成了 “Github”。建议统一更正为 “GitHub Copilot”。
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | |
| * @author <a href="https://github.com/github-copilot">GitHub Copilot</a> |
| * 文档地址:<a href="https://developers.weixin.qq.com/miniprogram/dev/server/API/face/api_queryverifyinfo">查询用户人脸核身真实验证结果</a> | ||
| * </p> | ||
| * | ||
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> |
There was a problem hiding this comment.
Javadoc 作者信息里品牌拼写应为 “GitHub”,这里写成了 “Github”。建议统一更正为 “GitHub Copilot”。
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | |
| * @author <a href="https://github.com/github-copilot">GitHub Copilot</a> |
| * 文档地址:<a href="https://developers.weixin.qq.com/miniprogram/dev/server/API/face/api_queryverifyinfo">查询用户人脸核身真实验证结果</a> | ||
| * </p> | ||
| * | ||
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> |
There was a problem hiding this comment.
Javadoc 作者信息里品牌拼写应为 “GitHub”,这里写成了 “Github”。建议统一更正为 “GitHub Copilot”。
| * @author <a href="https://github.com/github-copilot">Github Copilot</a> | |
| * @author <a href="https://github.com/github-copilot">GitHub Copilot</a> |
…/impl/WxMaFaceServiceImplTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…/WxMaFaceService.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…n/face/WxMaFaceGetVerifyIdResponse.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
- 将 calcCertHash 工具方法从 WxMaFaceServiceImpl 移到 WxMaFaceQueryVerifyInfoRequest 中 - 修复所有文件中 Github → GitHub 拼写错误 - 重构测试类:移除依赖真实接口的测试,只保留本地 calcCertHash 计算测试 - 修复测试类断言库混用问题,统一使用 TestNG 的 org.testng.Assert Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
已根据审查意见完成全部修改(commit
|
按照官方文档实现微信小程序人脸核身服务的两个后台接口,接口路径以
/cityservice/face/identify/为前缀。新增接口
getVerifyId— 根据用户实名信息(姓名+身份证)获取核身会话标识verifyId,供前端调用wx.requestFacialVerify使用queryVerifyInfo— 根据verifyId查询人脸核身真实结果;核身通过条件:errcode=0且verify_ret=10000新增文件
WxMaFaceServiceWxMaFaceServiceImplWxMaFaceGetVerifyIdRequest/Response、WxMaFaceQueryVerifyInfoRequest/ResponseWxMaApiUrlConstants.Face变更文件
WxMaService— 新增getFaceService()声明BaseWxMaServiceImpl— 注册服务实例并实现 gettercert_hash 计算
queryVerifyInfo需要传入cert_hash,WxMaFaceQueryVerifyInfoRequest内置了静态工具方法:计算结果与官方文档示例值完全一致。
使用示例
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.