1.下面是微信官方关于获取手机号的文档链接
2.微信基础库版本2.21.2以上时,即新版本库无需提前调用wx.login();旧版本必须先调用wx.login();
我的业务场景是为了微信授权一键登录,我这里做个新旧版本的兼容处理。
3.官方的代码示例,不能直接 CV 使用,下面粘上我个人亲测可用的示例代码
3.1先来一个触发按钮
<button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号码</button>
3.2如果微信基础库版本是旧版本( 2.21.2 以下)时,需要先调用wx.login()获取session_key 参数,之后调用getPhoneNumber 函数,此函数直接返回加密字符串,需要页面解密即可得到用户手机号。
此处附上解密工具js文件
WXBizDataCrypt.js文件内容如下:
var crypto = require('crypto')
function WXBizDataCrypt(appId, sessionKey) {
this.appId = appId
this.sessionKey = sessionKey
}
WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
// base64 decode
var sessionKey = new Buffer(this.sessionKey, 'base64')
encryptedData = new Buffer(encryptedData, 'base64')
iv = new Buffer(iv, 'base64')
try {
// 解密
var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
// 设置自动 padding 为 true,删除填充补位
decipher.setAutoPadding(true)
var decoded = decipher.update(encryptedData, 'binary', 'utf8')
decoded += decipher.final('utf8')
decoded = JSON.parse(decoded)
} catch (err) {
throw new Error('Illegal Buffer')
}
if (decoded.watermark.appid !== this.appId) {
throw new Error('Illegal Buffer')
}
return decoded
}
module.exports = WXBizDataCrypt
使用页面需要引入一下,路劲写成自己的,我的是放到根目录下的common文件夹下:
import WXBizDataCrypt from "@/common/WXBizDataCrypt.js";
3.3按钮绑定的函数 getPhoneNumber
//微信的login方法
wxAuthLogin(){
wx.login({
success:(res) => {
if (res.code) {
//发起网络请求
//此处请求自己的后台服务,并将输入参数 res.code 传给后台以获取输出参数wxopenid和session_key的值
} else {
console.log("微信登录失败:"+res.errMsg);
}
},
fail(res){
console.log(res.errMsg);
}
});
},
//获取手机号
getPhoneNumber (e) {
if(e.detail.errMsg == 'getPhoneNumber:fail user deny'){//拒绝获取手机号
console.log("授权失败,用户已拒绝!");
//拒绝后可以根据自己的实际场景添加业务逻辑
}else{//同意获取手机号
//此处Common.isExist 是我自定义的判断是否为空的函数,您可以修改为自己的判断非空的方法
if(Common.isExist(e.detail.code)){//如果存在code值,则当前环境为新版本
//此处根据入参 e.detail.code 请求后台接口,即可得到用户的手机号
}else{//微信基础库版本为旧版本
//解密方法,第一个参数为小程序的appid,第二个为调用wx.login()并请求后台之后返回的session_key
var pc = new WXBizDataCrypt("wx69e6361f588acbe5", this.sessionKey);
var data = pc.decryptData(e.detail.encryptedData , e.detail.iv);
console.log("解密后的手机号:"+data.purePhoneNumber);
}
}
}
4.平台差异说明,真机预览如下,会提示你的小程序名称申请,微信开发者工具中预览效果有所不一样,只要能调用成功即可。
5.后台服务接口
5.1 wx.login()请求的后台接口,代码示例如下,此处传入前端wx.login()获取到的code
private static final String appid = "wx****************";
private static final String secret = "7b****************e98bb6";
public static ReturnData getOpenIdAndSessionKey(String code) {
if(StringUtil.isEmpty(code)){
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取openid失败,参数code为空!");
}
String url = "https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&grant_type=authorization_code";
url += "&js_code="+code;
try {
CloseableHttpResponse response = HttpClients.createDefault().execute(new HttpGet(url));
String ret = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(ret);
if(StringUtil.isNotEmpty(jsonObject.getString("openid"))){
return new ReturnData(ReturnCode.SUCCESS.getCode(), ret, ReturnCode.SUCCESS.getMessage());
}
if("0".equals(jsonObject.getString("errcode"))){
return new ReturnData(ReturnCode.SUCCESS.getCode(), ret, ReturnCode.SUCCESS.getMessage());
}
logger.error("微信小程序获取openid错误:{}", jsonObject.getString("errmsg"));
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取openid错误");
} catch (ClientProtocolException e) {
logger.error("微信小程序获取openid异常,ClientProtocolException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取openid异常:ClientProtocolException");
} catch(IOException e){
logger.error("微信小程序获取openid异常,IOException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取openid异常:IOException");
} catch(Exception e){
logger.error("微信小程序获取openid异常,Exception:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取openid异常:Exception");
}
}
public static String getValueByKey(String ret,String key) {
JSONObject jsonObject = JSON.parseObject(ret);
return jsonObject.getString(key);
}
5.2新版本获取手机号的后台接口代码示例:
public static ReturnData getAccessToken() {
String url = "https://api.weixin.qq.com/cgi-bin/token?appid="+appid+"&secret="+secret+"&grant_type=client_credential";
try {
CloseableHttpResponse response = HttpClients.createDefault().execute(new HttpGet(url));
String ret = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(ret);
if(StringUtil.isNotEmpty(jsonObject.getString("access_token"))) {
return new ReturnData(ReturnCode.SUCCESS.getCode(), jsonObject.getString("access_token"), ReturnCode.SUCCESS.getMessage());
}
if("0".equals(jsonObject.getString("errcode"))){
return new ReturnData(ReturnCode.SUCCESS.getCode(), jsonObject.getString("access_token"), ReturnCode.SUCCESS.getMessage());
}
logger.error("微信小程序获取access_token错误:{}", jsonObject.getString("errmsg"));
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取access_token错误");
} catch (ClientProtocolException e) {
logger.error("微信小程序获取access_token异常,ClientProtocolException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取access_token异常:ClientProtocolException");
} catch(IOException e){
logger.error("微信小程序获取access_token异常,IOException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取access_token异常:IOException");
} catch(Exception e){
logger.error("微信小程序获取access_token异常,Exception:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取access_token异常:Exception");
}
}
public static ReturnData getPhone(String code) {
if(StringUtil.isEmpty(code)){
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取手机号失败,参数code为空!");
}
ReturnData returnData = getAccessToken();
if(!ReturnCode.SUCCESS.getCode().equals(returnData.getCode())){
return returnData;
}
String access_token = returnData.getResult();
String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+access_token;
try {
JSONObject param=new JSONObject();
param.put("code", code);
String ret = HttpClientUtil.sendHttpPost2(url, param.toJSONString());
JSONObject jsonObject = JSON.parseObject(ret);
if("0".equals(jsonObject.getString("errcode"))){
jsonObject = jsonObject.getJSONObject("phone_info");
return new ReturnData(ReturnCode.SUCCESS.getCode(), jsonObject.getString("purePhoneNumber"), ReturnCode.SUCCESS.getMessage());
}
logger.error("微信小程序获取手机号错误:{}", jsonObject.getString("errmsg"));
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取手机号错误");
} catch (ClientProtocolException e) {
logger.error("微信小程序获取手机号异常,ClientProtocolException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取手机号异常:ClientProtocolException");
} catch(IOException e){
logger.error("微信小程序获取手机号异常,IOException:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取手机号异常:IOException");
} catch(Exception e){
logger.error("微信小程序获取手机号异常,Exception:{}", e);
return new ReturnData(ReturnCode.FAIL.getCode(), "微信小程序获取手机号异常:Exception");
}
}
上面获取手机号的方法内用到一个HttpClientUtil.sendHttpPost2 方法的代码如下:
/**
* 向指定 URL 发送POST方法的请求(参数不带名称)
*/
public static String sendHttpPost2(String url, String param) throws IOException {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(300000);
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
// out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
6.到此一个完整的微信小程序获取用户手机号的完整实战案例就结束了,如有错误还请各位大佬能指正。欢迎评论区留言咨询或者讨论。
题外话:欢迎大家微信搜索#民谣嗑学家 ,关注我的个人公众号,我是一名爱代码,爱民谣,爱生活的业余吉他爱好者的Java 程序员,致力于向全栈发展的全能程序员。有想跟作者交朋友的可以关注我公众号,获取我的联系方式,我们可以一起学习,一起进步,业余时间可以一起娱乐娱乐,哈哈^_^。