后边要做一个微信小程序,并要能获取用户微信绑定的手机号码。而小程序开发文档上边提供的获取手机号码的接口(getPhoneNumber())返回的是密文,需要服务器端进行解密,但是官方提供的开发文档一如既往的乱,如果没有对小程序开发文档有一个整体的了解,搞懂解密流程还是有点难的。这里把小程序从请求用户授权获取手机号码直至获取到手机号码明文的整个流程串了起来,方便迅速了解,如下:一. 前端相关操作:一. 前端相关操作:一. 前端相关操作:1. 请求用户授权获取手机号码:1. 请求用户授权获取手机号码:因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用
js:
Page({
getPhoneNumber: function(e) {

if(e.detail.errMsg == "getPhoneNumber:fail user deny") return;
//用户允许授权

console.log("lv", e.detail.iv); //包括敏感数据在内的完整用户信息的加密数据,需要解密

console.log(e.detail.encryptedData); //加密算法的初始向量,解密需要用到

......
}
})
Page({
getPhoneNumber: function(e) {

if(e.detail.errMsg == "getPhoneNumber:fail user deny") return;
//用户允许授权

console.log("lv", e.detail.iv); //包括敏感数据在内的完整用户信息的加密数据,需要解密

console.log(e.detail.encryptedData); //加密算法的初始向量,解密需要用到

......
}
})2. 访问小程序登录接口:2. 访问小程序登录接口:小程序调用wx.login()获取临时登录凭证code,并传到开发者服务器。
Page({
getPhoneNumber: function(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv) //包括敏感数据在内的完整用户信息的加密数据,需要解密
console.log(e.detail.encryptedData) //加密算法的初始向量,解密需要用到
wx.login({

success: res => {

if(res.code){

console.log(res.code)

}

}
})
}
})
Page({
getPhoneNumber: function(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv) //包括敏感数据在内的完整用户信息的加密数据,需要解密
console.log(e.detail.encryptedData) //加密算法的初始向量,解密需要用到
wx.login({

success: res => {

if(res.code){

console.log(res.code)

}

}
})
}
})3. 访问腾讯服务器的登录凭证校验接口:3. 访问腾讯服务器的登录凭证校验接口:注:官方推荐放到服务器端进行,这里为了方便,就放在前端请求了。这里要注意传入参数:






appid



小程序唯一标识





secret



小程序的 app secret





js_code



登录时获取的 code





grant_type



填写为 authorization_code








appid



小程序唯一标识





secret



小程序的 app secret





js_code



登录时获取的 code





grant_type



填写为 authorization_code





appid



小程序唯一标识

appid 小程序唯一标识

secret



小程序的 app secret

secret 小程序的 app secret

js_code



登录时获取的 code

js_code 登录时获取的 code

grant_type



填写为 authorization_code

grant_type 填写为 authorization_code
//2. 访问登录凭证校验接口获取session_key
wx.request({

url: "https://api.weixin.qq.com/sns/jscode2session",

data: {

'appid': "xxxxxxxx",

'secret': "xxxxxxxx",

'js_code': res.code,

'grant_type': "authorization_code"

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function(data) {

console.log("data", data.data.session_key)

},

fail: function(err) {

console.log(err);

}
})
//2. 访问登录凭证校验接口获取session_key
wx.request({

url: "https://api.weixin.qq.com/sns/jscode2session",

data: {

'appid': "xxxxxxxx",

'secret': "xxxxxxxx",

'js_code': res.code,

'grant_type': "authorization_code"

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function(data) {

console.log("data", data.data.session_key)

},

fail: function(err) {

console.log(err);

}
})4. 自己的服务器端进行解密4. 自己的服务器端进行解密注:解密接口可以使用腾讯官方的demo进行改造,具体改造会在后面说明。
//3. 解密
wx.request({

url: 'http://xxxxx.com/demo/demo.php',//腾讯官方demo改造的接口页面

data: {

'encryptedData': encodeURIComponent(e.detail.encryptedData),//需要进行编码

'iv': e.detail.iv,

'session_key': data.data.session_key

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function(data2) {

console.log(data2.data.phoneNumber)

if(data2.statusCode == 200) {

self.setData({

phone: data2.data.phoneNumber

})

}

},

fail: function(err) {

console.log(err);

}
})
//3. 解密
wx.request({

url: 'http://xxxxx.com/demo/demo.php',//腾讯官方demo改造的接口页面

data: {

'encryptedData': encodeURIComponent(e.detail.encryptedData),//需要进行编码

'iv': e.detail.iv,

'session_key': data.data.session_key

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function(data2) {

console.log(data2.data.phoneNumber)

if(data2.statusCode == 200) {

self.setData({

phone: data2.data.phoneNumber

})

}

},

fail: function(err) {

console.log(err);

}
})js部分整体代码如下:
getPhoneNumber: function (e) {
if (e.detail.errMsg == "getPhoneNumber:fail user deny") return;
//用户允许授权
console.log("lv", e.detail.iv);
console.log(e.detail.encryptedData);
wx.showLoading()
var self=this
//1. 调用登录接口获取临时登录code
wx.login({
success: res => {
if(res.code){

//2. 访问登录凭证校验接口获取session_key、openid

wx.request({

url: "https://api.weixin.qq.com/sns/jscode2session",

data: {

'appid': "wxcc41e47562b08129",

'secret': "50e4379d67a6860d18157c53dc6ac3c2",

'js_code': res.code,

'grant_type': "authorization_code"

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function (data) {

console.log("data", data)

if(data.statusCode==200){

//3. 解密

wx.request({

url: 'http://qdy8.gotoip4.com/demo/demo.php',

data: {

'encryptedData': e.detail.encryptedData,

'iv': e.detail.iv,

'session_key': data.data.session_key

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function (data2) {

wx.hideLoading()

console.log(data2.data.phoneNumber)

if (data2.statusCode == 200 && data2.data.phoneNumber) {

self.setData({

phone: data2.data.phoneNumber

})

}

},

fail: function (err) {

console.log(err);

}

})

}

},

fail: function (err) {

console.log(err);

}

})
}


}
})
}
getPhoneNumber: function (e) {
if (e.detail.errMsg == "getPhoneNumber:fail user deny") return;
//用户允许授权
console.log("lv", e.detail.iv);
console.log(e.detail.encryptedData);
wx.showLoading()
var self=this
//1. 调用登录接口获取临时登录code
wx.login({
success: res => {
if(res.code){

//2. 访问登录凭证校验接口获取session_key、openid

wx.request({

url: "https://api.weixin.qq.com/sns/jscode2session",

data: {

'appid': "wxcc41e47562b08129",

'secret': "50e4379d67a6860d18157c53dc6ac3c2",

'js_code': res.code,

'grant_type': "authorization_code"

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function (data) {

console.log("data", data)

if(data.statusCode==200){

//3. 解密

wx.request({

url: 'http://qdy8.gotoip4.com/demo/demo.php',

data: {

'encryptedData': e.detail.encryptedData,

'iv': e.detail.iv,

'session_key': data.data.session_key

},

method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT

header: {

'content-type': 'application/json'

}, // 设置请求的 header

success: function (data2) {

wx.hideLoading()

console.log(data2.data.phoneNumber)

if (data2.statusCode == 200 && data2.data.phoneNumber) {

self.setData({

phone: data2.data.phoneNumber

})

}

},

fail: function (err) {

console.log(err);

}

})

}

},

fail: function (err) {

console.log(err);

}

})
}


}
})
}二. 后端接口:二. 后端接口:二. 后端接口:微信官方提供了多种编程语言的示例代码(示例代码)。每种语言类型的接口名字均一致,调用方式可以参照示例。示例代码如果只是学习研究,可以买个经济型的虚拟主机,一年才几十块钱,不过这种虚拟主机以php居多,所以这里以php为例进行改造,接收前端请求。官方demo下载后结构如下:对demo.php进行改造:

include_once "wxBizDataCrypt.php";

/**
* sessionKey/encryptedData/iv参数均从url中获取,并赋给相应变量
*/
$appid = 'xxxxxxxx';
$sessionKey = $_REQUEST['session_key'];
$encryptedData=$_REQUEST['encryptedData'];
$iv = $_REQUEST['iv'];

$pc = new WXBizDataCrypt($appid, $sessionKey);
$errCode = $pc->decryptData($encryptedData, $iv, $data );

if ($errCode == 0) {
print($data . "\n");
} else {
print($errCode . "\n");
}
?>

include_once "wxBizDataCrypt.php";

/**
* sessionKey/encryptedData/iv参数均从url中获取,并赋给相应变量
*/
$appid = 'xxxxxxxx';
$sessionKey = $_REQUEST['session_key'];
$encryptedData=$_REQUEST['encryptedData'];
$iv = $_REQUEST['iv'];

$pc = new WXBizDataCrypt($appid, $sessionKey);
$errCode = $pc->decryptData($encryptedData, $iv, $data );

if ($errCode == 0) {
print($data . "\n");
} else {
print($errCode . "\n");
}
?>将php的三个demo文件上传虚拟主机:然后就可以直接访问demo.php文件作为接口了。三. 容易出现的异常:三. 容易出现的异常:三. 容易出现的异常:1. 访问微信的登录凭证校验接口获取session_key时,如果报出如下错误,则需清除全部缓存,重新编译(应该是更改过appid,开发工具的坑,不清除全部缓存,会出现这个错误):
invalid code, hints: [ req_id: CPAsWa0325ha57 ]
invalid code, hints: [ req_id: CPAsWa0325ha57 ]2.解密接口返回-41003,则检查接口参数: