From bdf947e2ca80887be0ac1d93bc67054473477b0d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 31 Jul 2026 00:17:22 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20#4078=20=E3=80=90=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E3=80=91=E8=8E=B7=E5=8F=96=E6=89=8B=E6=9C=BA=E5=8F=B7?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=E6=94=AF=E6=8C=81openid=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/common/util/DataUtils.java | 6 ++- .../weixin/common/util/DataUtilsTest.java | 10 ++++ .../wx/miniapp/api/WxMaUserService.java | 13 +++++ .../miniapp/api/impl/BaseWxMaServiceImpl.java | 2 +- .../miniapp/api/impl/WxMaUserServiceImpl.java | 9 ++++ .../WxMaUserServiceImplPhoneNumberTest.java | 50 +++++++++++++++++++ 6 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplPhoneNumberTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java index 095363cf8..2e9f5d4c7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java @@ -17,8 +17,10 @@ public class DataUtils { */ public static E handleDataWithSecret(E data) { E dataForLog = data; - if (data instanceof String && StringUtils.contains((String) data, "secret=")) { - dataForLog = (E) RegExUtils.replaceAll((String) data, "(^|[?&])secret=[^&]*", "$1secret=******"); + if (data instanceof String) { + String stringData = (String) data; + stringData = RegExUtils.replaceAll(stringData, "(^|[?&])secret=[^&]*", "$1secret=******"); + dataForLog = (E) RegExUtils.replaceAll(stringData, "(\\\"openid\\\"\\s*:\\s*\\\")[^\\\"]*(\\\")", "$1******$2"); } return dataForLog; } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java index 1bda61a23..c5088e78c 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java @@ -47,4 +47,14 @@ public class DataUtilsTest { assertFalse(s.contains("%2F"), "Encoded characters in the secret must be masked too"); assertTrue(s.contains("&secret=******&"), "Secret should be replaced with asterisks"); } + + @Test + public void testHandleDataWithOpenidInJson() { + String data = "{\"code\":\"phone-code\",\"openid\":\"user-openid\"}"; + + String result = DataUtils.handleDataWithSecret(data); + + assertFalse(result.contains("user-openid")); + assertTrue(result.contains("\"openid\":\"******\"")); + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java index bc8b69a14..65b817f79 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java @@ -73,6 +73,19 @@ public interface WxMaUserService { */ WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException; + /** + * 获取手机号信息,并校验手机号获取凭证与用户的绑定关系。 + * + * @param code 每个code只能使用一次,code的有效期为5min。code获取方式参考手机号快速验证组件 + * @param openid 用户openid,传入后微信服务端将校验其与code的绑定关系 + * @return 用户手机号信息 + * @throws WxErrorException . + * @apiNote 该接口用于将code换取用户手机号。 + */ + default WxMaPhoneNumberInfo getPhoneNumber(String code, String openid) throws WxErrorException { + return this.getPhoneNumber(code); + } + /** * 获取手机号信息,基础库:2.21.2及以上或2023年8月28日起 * diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java index 9d6c2c0fa..bf69439a6 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java @@ -374,7 +374,7 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH Map headers, String data) throws WxErrorException { - String dataForLog = "Headers: " + headers.toString() + " Body: " + data; + String dataForLog = "Headers: " + headers.toString() + " Body: " + DataUtils.handleDataWithSecret(data); return executeWithRetry( (uriWithAccessToken) -> executor.execute(uriWithAccessToken, headers, data, WxType.MiniApp), uri, diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java index c9c7a7b77..abbb021e8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java @@ -16,6 +16,7 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.SignUtils; import me.chanjar.weixin.common.util.json.GsonParser; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; import java.util.Map; @@ -67,8 +68,16 @@ public class WxMaUserServiceImpl implements WxMaUserService { @Override public WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException { + return this.getPhoneNumber(code, null); + } + + @Override + public WxMaPhoneNumberInfo getPhoneNumber(String code, String openid) throws WxErrorException { JsonObject param = new JsonObject(); param.addProperty("code", code); + if (StringUtils.isNotBlank(openid)) { + param.addProperty("openid", openid); + } String responseContent = this.service.post(GET_PHONE_NUMBER_URL, param.toString()); JsonObject response = GsonParser.parse(responseContent); if (response.has(PHONE_INFO)) { diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplPhoneNumberTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplPhoneNumberTest.java new file mode 100644 index 000000000..610cd13bf --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImplPhoneNumberTest.java @@ -0,0 +1,50 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import com.google.gson.JsonObject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonParser; +import org.mockito.ArgumentCaptor; +import org.testng.annotations.Test; + +import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.User.GET_PHONE_NUMBER_URL; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + +/** + * {@link WxMaUserServiceImpl} 获取手机号接口的单元测试。 + */ +public class WxMaUserServiceImplPhoneNumberTest { + + @Test + public void shouldSendOpenidWhenGettingPhoneNumber() throws WxErrorException { + WxMaService wxMaService = mock(WxMaService.class); + when(wxMaService.post(anyString(), anyString())).thenReturn("{\"phone_info\":{}}"); + + new WxMaUserServiceImpl(wxMaService).getPhoneNumber("phone-code", "user-openid"); + + ArgumentCaptor requestBody = ArgumentCaptor.forClass(String.class); + verify(wxMaService).post(eq(GET_PHONE_NUMBER_URL), requestBody.capture()); + JsonObject request = GsonParser.parse(requestBody.getValue()); + assertEquals(request.get("code").getAsString(), "phone-code"); + assertEquals(request.get("openid").getAsString(), "user-openid"); + } + + @Test + public void shouldIgnoreBlankOpenidWhenGettingPhoneNumber() throws WxErrorException { + WxMaService wxMaService = mock(WxMaService.class); + when(wxMaService.post(anyString(), anyString())).thenReturn("{\"phone_info\":{}}"); + + new WxMaUserServiceImpl(wxMaService).getPhoneNumber("phone-code", " "); + + ArgumentCaptor requestBody = ArgumentCaptor.forClass(String.class); + verify(wxMaService).post(eq(GET_PHONE_NUMBER_URL), requestBody.capture()); + JsonObject request = GsonParser.parse(requestBody.getValue()); + assertFalse(request.has("openid")); + } +}