Skip to content

Commit 492ac60

Browse files
committed
🎨 #4078 【小程序】获取手机号的方法支持openid校验
1 parent 15f5d88 commit 492ac60

6 files changed

Lines changed: 87 additions & 3 deletions

File tree

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ public class DataUtils {
1717
*/
1818
public static <E> E handleDataWithSecret(E data) {
1919
E dataForLog = data;
20-
if (data instanceof String && StringUtils.contains((String) data, "secret=")) {
21-
dataForLog = (E) RegExUtils.replaceAll((String) data, "(^|[?&])secret=[^&]*", "$1secret=******");
20+
if (data instanceof String) {
21+
String stringData = (String) data;
22+
stringData = RegExUtils.replaceAll(stringData, "(^|[?&])secret=[^&]*", "$1secret=******");
23+
dataForLog = (E) RegExUtils.replaceAll(stringData, "(\\\"openid\\\"\\s*:\\s*\\\")[^\\\"]*(\\\")", "$1******$2");
2224
}
2325
return dataForLog;
2426
}

weixin-java-common/src/test/java/me/chanjar/weixin/common/util/DataUtilsTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,14 @@ public void testHandleDataWithSecretEncodedValue() {
4747
assertFalse(s.contains("%2F"), "Encoded characters in the secret must be masked too");
4848
assertTrue(s.contains("&secret=******&"), "Secret should be replaced with asterisks");
4949
}
50+
51+
@Test
52+
public void testHandleDataWithOpenidInJson() {
53+
String data = "{\"code\":\"phone-code\",\"openid\":\"user-openid\"}";
54+
55+
String result = DataUtils.handleDataWithSecret(data);
56+
57+
assertFalse(result.contains("user-openid"));
58+
assertTrue(result.contains("\"openid\":\"******\""));
59+
}
5060
}

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ public interface WxMaUserService {
7373
*/
7474
WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException;
7575

76+
/**
77+
* 获取手机号信息,并校验手机号获取凭证与用户的绑定关系。
78+
*
79+
* @param code 每个code只能使用一次,code的有效期为5min。code获取方式参考<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html">手机号快速验证组件</a>
80+
* @param openid 用户openid,传入后微信服务端将校验其与code的绑定关系
81+
* @return 用户手机号信息
82+
* @throws WxErrorException .
83+
* @apiNote 该接口用于将code换取用户手机号。
84+
*/
85+
default WxMaPhoneNumberInfo getPhoneNumber(String code, String openid) throws WxErrorException {
86+
return this.getPhoneNumber(code);
87+
}
88+
7689
/**
7790
* 获取手机号信息,基础库:2.21.2及以上或2023年8月28日起
7891
*

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ public WxMaApiResponse execute(
374374
Map<String, String> headers,
375375
String data)
376376
throws WxErrorException {
377-
String dataForLog = "Headers: " + headers.toString() + " Body: " + data;
377+
String dataForLog = "Headers: " + headers.toString() + " Body: " + DataUtils.handleDataWithSecret(data);
378378
return executeWithRetry(
379379
(uriWithAccessToken) -> executor.execute(uriWithAccessToken, headers, data, WxType.MiniApp),
380380
uri,

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import me.chanjar.weixin.common.util.SignUtils;
1717
import me.chanjar.weixin.common.util.json.GsonParser;
1818
import org.apache.commons.codec.digest.DigestUtils;
19+
import org.apache.commons.lang3.StringUtils;
1920

2021
import java.util.Map;
2122

@@ -67,8 +68,16 @@ public WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedDat
6768

6869
@Override
6970
public WxMaPhoneNumberInfo getPhoneNumber(String code) throws WxErrorException {
71+
return this.getPhoneNumber(code, null);
72+
}
73+
74+
@Override
75+
public WxMaPhoneNumberInfo getPhoneNumber(String code, String openid) throws WxErrorException {
7076
JsonObject param = new JsonObject();
7177
param.addProperty("code", code);
78+
if (StringUtils.isNotBlank(openid)) {
79+
param.addProperty("openid", openid);
80+
}
7281
String responseContent = this.service.post(GET_PHONE_NUMBER_URL, param.toString());
7382
JsonObject response = GsonParser.parse(responseContent);
7483
if (response.has(PHONE_INFO)) {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cn.binarywang.wx.miniapp.api.impl;
2+
3+
import cn.binarywang.wx.miniapp.api.WxMaService;
4+
import com.google.gson.JsonObject;
5+
import me.chanjar.weixin.common.error.WxErrorException;
6+
import me.chanjar.weixin.common.util.json.GsonParser;
7+
import org.mockito.ArgumentCaptor;
8+
import org.testng.annotations.Test;
9+
10+
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.User.GET_PHONE_NUMBER_URL;
11+
import static org.mockito.ArgumentMatchers.anyString;
12+
import static org.mockito.ArgumentMatchers.eq;
13+
import static org.mockito.Mockito.mock;
14+
import static org.mockito.Mockito.verify;
15+
import static org.mockito.Mockito.when;
16+
import static org.testng.Assert.assertEquals;
17+
import static org.testng.Assert.assertFalse;
18+
19+
/**
20+
* {@link WxMaUserServiceImpl} 获取手机号接口的单元测试。
21+
*/
22+
public class WxMaUserServiceImplPhoneNumberTest {
23+
24+
@Test
25+
public void shouldSendOpenidWhenGettingPhoneNumber() throws WxErrorException {
26+
WxMaService wxMaService = mock(WxMaService.class);
27+
when(wxMaService.post(anyString(), anyString())).thenReturn("{\"phone_info\":{}}");
28+
29+
new WxMaUserServiceImpl(wxMaService).getPhoneNumber("phone-code", "user-openid");
30+
31+
ArgumentCaptor<String> requestBody = ArgumentCaptor.forClass(String.class);
32+
verify(wxMaService).post(eq(GET_PHONE_NUMBER_URL), requestBody.capture());
33+
JsonObject request = GsonParser.parse(requestBody.getValue());
34+
assertEquals(request.get("code").getAsString(), "phone-code");
35+
assertEquals(request.get("openid").getAsString(), "user-openid");
36+
}
37+
38+
@Test
39+
public void shouldIgnoreBlankOpenidWhenGettingPhoneNumber() throws WxErrorException {
40+
WxMaService wxMaService = mock(WxMaService.class);
41+
when(wxMaService.post(anyString(), anyString())).thenReturn("{\"phone_info\":{}}");
42+
43+
new WxMaUserServiceImpl(wxMaService).getPhoneNumber("phone-code", " ");
44+
45+
ArgumentCaptor<String> requestBody = ArgumentCaptor.forClass(String.class);
46+
verify(wxMaService).post(eq(GET_PHONE_NUMBER_URL), requestBody.capture());
47+
JsonObject request = GsonParser.parse(requestBody.getValue());
48+
assertFalse(request.has("openid"));
49+
}
50+
}

0 commit comments

Comments
 (0)