1
0
mirror of synced 2026-10-07 23:39:43 +08:00

🎨 #4078 【小程序】获取手机号的方法支持openid校验

This commit is contained in:
Binary Wang
2026-07-31 00:17:22 +08:00
committed by GitHub
parent 8c5d917db9
commit bdf947e2ca
6 changed files with 87 additions and 3 deletions

View File

@@ -17,8 +17,10 @@ public class DataUtils {
*/
public static <E> 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;
}

View File

@@ -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\":\"******\""));
}
}

View File

@@ -73,6 +73,19 @@ public interface WxMaUserService {
*/
WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException;
/**
* 获取手机号信息,并校验手机号获取凭证与用户的绑定关系。
*
* @param code 每个code只能使用一次,code的有效期为5min。code获取方式参考<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html">手机号快速验证组件</a>
* @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日起
*

View File

@@ -374,7 +374,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
Map<String, String> 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,

View File

@@ -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)) {

View File

@@ -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<String> 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<String> 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"));
}
}