先吐槽,由于偷懒 某度一下 没发现完整的代码可以用,需要东拼西凑,没有拿来主义的感觉。
获取手机号
获取微信用户绑定的手机号,需先调用wx.login接口。
因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用 button 组件的点击来触发。
注意:目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。
以上是官方说的,根据官方说的实现
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
流程:
1.通过wx.login(Object object)获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key)
wx.login({
success: res => {
wx.request({
url: 'http://192.168.1.128:8088/app/wx/jscodeToSession',
method: "POST",
header: {
'content-type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
dataType: 'json',
data: {
js_code: res.code,
},
success(res) {
that.globalData.session_key = res.data.data.session_key;
that.globalData.openid = res.data.data.openid;
},
fail(res) {
console.log('拉取用户openid失败,将无法正常使用开放接口等服务', res)
}
});
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
@RequestMapping(value = "/jscodeToSession", produces = "application/json;charset=UTF-8", method = { RequestMethod.GET,RequestMethod.POST })
@ResponseBody
public Map<String,Object> jscodeToSession(String js_code) {//js_code 登录(wx.login())时获取的 code
Map<String,Object> reMap = new HashMap<String,Object>();
String v_appid = "小程序 appId";
String v_secret = "小程序 appSecret";
String readInterFaceFromUrlByUTF8 = ToolUtil.readInterFaceFromUrlByUTF8("https://api.weixin.qq.com/sns/jscode2session?appid="+v_appid+"&secret="+v_secret+"&js_code="+js_code+"&grant_type=authorization_code");
JSONObject root = JSONObject.parseObject(readInterFaceFromUrlByUTF8);
JSONObject data = new JSONObject();
if(root.containsKey("errcode")){
reMap.put("success", false);
data.put("errcode", root.getString("errcode"));
data.put("errmsg", root.getString("errmsg"));
reMap.put("data", data);
}else{
reMap.put("success", true);
data.put("session_key", root.getString("session_key"));
data.put("openid", root.getString("openid"));
reMap.put("data", data);
}
return reMap;
}
public static String readInterFaceFromUrlByUTF8(String UrlStr) {
return readInterFaceFromUrl(UrlStr, "utf-8");
}
public static String readInterFaceFromUrl(String UrlStr, String encode) {
if (UrlStr.equalsIgnoreCase("") || UrlStr == null)
return "";
String reVal = "";
URL url;
HttpURLConnection httpConnection = null;
try {
url = new URL(UrlStr);
URLConnection URLconnection = url.openConnection();
httpConnection = (HttpURLConnection) URLconnection;
// httpConnection.setRequestMethod("POST");
int responseCode = httpConnection.getResponseCode();
System.out.println(responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream urlStream = httpConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(urlStream, encode));
String sCurrentLine = "";
String sTotalString = "";
while ((sCurrentLine = bufferedReader.readLine()) != null) {
sTotalString += sCurrentLine;
}
reVal = sTotalString;
} else {
System.err.println("读取接口失败");
}
} catch (Exception e) {
// e.printStackTrace();
System.err.println("读取接口异常");
reVal = "";
} finally {
httpConnection.disconnect();
}
return reVal;
}
2.通过button组件来发起获取手机号接口,将事件回调获取到微信服务器返回的加密数据, 再结合 session_key
以及 app_id
进行解密获取手机号
// button组建 放在 wxml里面
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
//放到对应的js里面
getPhoneNumber(e) {
if (e.detail.errMsg == "getPhoneNumber:ok") {
wx.request({
url: 'http://192.168.1.128:8088/app/wx/getPhoneNumber',
method: "POST",
header: {
'content-type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
dataType: 'json',
data: {
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
session_key: app.globalData.session_key
},
success(res) {
console.log(res);
},
fail(res) {
}
});
}
}
@RequestMapping(value = "/getPhoneNumber", produces = "application/json;charset=UTF-8", method = { RequestMethod.GET,RequestMethod.POST })
@ResponseBody
public Map<String,Object> getPhoneNumber(String session_key,String encryptedData,String iv) {
Map<String,Object> reMap = new HashMap<String,Object>();
String v_result = analysisPhoneNumber(session_key,encryptedData,iv);
JSONObject resultObject = JSONObject.parseObject(v_result);
reMap.put("phoneNumber", resultObject.getString("phoneNumber"));
reMap.put("purePhoneNumber", resultObject.getString("purePhoneNumber"));
reMap.put("countryCode", resultObject.getString("countryCode"));//国家代码
return reMap;
}
/**
* 解密手机号
* @author
* @param session_key
* @param encryptedData
* @param iv
* @return
*/
private static String analysisPhoneNumber(String session_key,String encryptedData,String iv ){
byte[] dataByte = Base64.decode(encryptedData);
byte[] keyByte = Base64.decode(session_key);
byte[] ivByte = Base64.decode(iv);
try {
int base = 16;
if (keyByte.length % base != 0) {
int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
keyByte = temp;
}
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
byte[] resultByte = cipher.doFinal(dataByte);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
return result;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
至此完事。