如图:

小程序代码:
第一步,登录,获取用户的 session_key;
第二步,点击按钮调用 bindgetphonenumber 事件,通过该事件得到 encryptedData 和 iv
第三步,把session_key,encryptedData 和 iv 传递给后端解密得到用户的手机号信息
文章结尾有我的小程序util.js文件。
登录代码:(我是在app.js 里面统一封装的登录模块,如果有自己的登录模块,可以无视这段代码,把session_key放到第二段代码就可以)
- //app.js
- const util = require('./utils/util.js');
- App({
- onLaunch: function() {
- var that = this;
- // wx.login
- that.login = (resolve) => {
- wx.login({
- success: (res) => {
- if (res.code) {
- that.loginRequest(res.code, resolve);
- }
- },
- })
- }
- // session定时器
- that.sessionIsExpire = (resolve) => {
- const session = wx.getStorageSync('session_key');
- const deadLine = wx.getStorageSync('deadline');
- const nowDate = new Date().getTime();
- if (session && deadLine) {
- if (nowDate - deadLine >= 1000 * 60 * 60 * 24) {
- that.login(resolve)
- } else {
- wx.checkSession({
- success() {
- // session_key 未过期,并且在本生命周期一直有效
- resolve(session)
- },
- fail() {
- // session_key 已经失效,需要重新执行登录流程
- that.login(resolve)
- }
- })
- }
- } else {
- that.login(resolve)
- }
- }
-
- // 获取session
- that.pro_getSession = new Promise((resolve) => {
- that.sessionIsExpire(resolve)
- })
- // 请求login.do接口得到session
- that.loginRequest = (code, resolve) => {
- var url = '/login.php';
- var data = {
- code
- }
- util.request(url, 'post', data, '', (res) => {
- console.log('登录了')
- if (res.data.success == true) {
- const session = res.session_key;
- resolve(session)
- wx.setStorageSync('openid', res.openid);
- wx.setStorageSync('session_key', session);
- wx.setStorageSync('deadline', new Date().getTime())
- } else {
- resolve(1)
- }
- }, (fail) => {
- resolve(1)
- })
- }
- },
-
-
- globalData: {
- userInfo: null
- }
- })
小程序代码片段2: 获取手机号页面的代码
- <button class="motto-font" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">
- 获取手机号
- </button>
- // 获取手机号码
- getPhoneNumber: function (e) {
- console.log(e)
-
- if (e.detail.errMsg == 'getPhoneNumber:fail') {
- console.log(ErrMsg);
- that.showToast_fail('未获取到手机号码');
- return false;
- } else if (e.detail.iv == undefined || !e.detail.iv) {
- that.showToast_fail('授权失败');
- return false;
- } else {
- // 解密手机号接口
- var url = "/getTelNumber.php";
- var params = {
- session_key: wx.getStorageSync('session_key'),
- encryptedData: e.detail.encryptedData,
- iv: e.detail.iv
- };
- util.request(url, 'post', params, '', (res) => {
- that.setData({
- phone: res.data.phoneNumber,
- })
- wx.reLaunch({
- url: '../index/index',
- })
- }, function () {
- that.showToast_fail('获取手机号失败');
- })
- }
- },
后端实现代码:
登录接口如图

login.php代码 (这个接口返回的是一个JSON对象)
- <?php
- header("Content-Type:text/html;charset=utf8");
- header("Access-Control-Allow-Origin: *"); //解决跨域
- header('Access-Control-Allow-Methods:POST');// 响应类型
- header('Access-Control-Allow-Headers:*'); // 响应头设置
- error_reporting(E_ALL);
- $code = $_POST['code'];
- $url='https://api.weixin.qq.com/sns/jscode2session?appid=wx4d7fcc145ca8013b&secret=c58ac54c1bf4c2de7c07221e547a4218&js_code='.$code.'&grant_type=authorization_code';
- $html = file_get_contents($url);
- print($html);
- ?>
getTelNumber.php代码如图

代码:
- <?php
- header("Content-Type:text/html;charset=utf8");
- header("Access-Control-Allow-Origin: *"); //解决跨域
- header('Access-Control-Allow-Methods:POST');// 响应类型
- header('Access-Control-Allow-Headers:*'); // 响应头设置
-
- $appid = 'wx4d7fcc145ca8013b';
- $sessionKey = $_POST['session_key'];
- $encryptedData = $_POST['encryptedData'];
- $iv = $_POST['iv'];
- include_once "wxBizDataCrypt.php";
- $data = '';
- $pc = new WXBizDataCrypt($appid, $sessionKey);
- $errCode = $pc->decryptData($encryptedData, $iv, $data );
-
- if ($errCode == 0) {
- print($data . "\n");
- } else {
- print($errCode . "\n");
- }
- ?>
这里有引用到两个文件,放到相同的目录下就行
wxBizDataCrypt.php
- <?php
-
- /**
- * 对微信小程序用户加密数据的解密示例代码.
- *
- * @copyright Copyright (c) 1998-2014 Tencent Inc.
- */
-
-
- include_once "errorCode.php";
-
-
- class WXBizDataCrypt
- {
- private $appid;
- private $sessionKey;
-
- /**
- * 构造函数
- * @param $sessionKey string 用户在小程序登录后获取的会话密钥
- * @param $appid string 小程序的appid
- */
- public function __construct( $appid, $sessionKey)
- {
- $this->sessionKey = $sessionKey;
- $this->appid = $appid;
- }
-
-
- /**
- * 检验数据的真实性,并且获取解密后的明文.
- * @param $encryptedData string 加密的用户数据
- * @param $iv string 与用户数据一同返回的初始向量
- * @param $data string 解密后的原文
- *
- * @return int 成功0,失败返回对应的错误码
- */
- public function decryptData( $encryptedData, $iv, &$data )
- {
- if (strlen($this->sessionKey) != 24) {
- return ErrorCode::$IllegalAesKey;
- }
- $aesKey=base64_decode($this->sessionKey);
-
-
- if (strlen($iv) != 24) {
- return ErrorCode::$IllegalIv;
- }
- $aesIV=base64_decode($iv);
-
- $aesCipher=base64_decode($encryptedData);
-
- $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
-
- $dataObj=json_decode( $result );
- if( $dataObj == NULL )
- {
- return ErrorCode::$IllegalBuffer;
- }
- if( $dataObj->watermark->appid != $this->appid )
- {
- return ErrorCode::$IllegalBuffer;
- }
- $data = $result;
- return ErrorCode::$OK;
- }
-
- }
errorCode.php
- <?php
-
- /**
- * error code 说明.
- * <ul>
- * <li>-41001: encodingAesKey 非法</li>
- * <li>-41003: aes 解密失败</li>
- * <li>-41004: 解密后得到的buffer非法</li>
- * <li>-41005: base64加密失败</li>
- * <li>-41016: base64解密失败</li>
- * </ul>
- */
- class ErrorCode
- {
- public static $OK = 0;
- public static $IllegalAesKey = -41001;
- public static $IllegalIv = -41002;
- public static $IllegalBuffer = -41003;
- public static $DecodeBase64Error = -41004;
- }
-
- ?>
小程序util.js文件
- const formatTime = date => {
- const year = date.getFullYear()
- const month = date.getMonth() + 1
- const day = date.getDate()
- const hour = date.getHours()
- const minute = date.getMinutes()
- const second = date.getSeconds()
-
- return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
- }
- // 网络请求
- const request = function(url, method, data, msg, succ, fail, com) {
- // 小程序顶部显示Loading
- wx.showNavigationBarLoading();
- if (msg != "") {
- wx.showLoading({
- title: msg
- })
- }
- wx.request({
- url: 'http://localhost/shige/minP'+url,
- data: data,
- header: {
- 'content-type': 'application/x-www-form-urlencoded'
- },
- method: method,
- success: res => {
- if (succ) succ(res);
- },
- fail: err => {
- wx.showToast({
- title: '网络错误,请稍后再试···',
- icon:'none'
- })
- if (fail) fail(err);
- },
- complete: com => {
- wx.hideNavigationBarLoading();
- if (msg != "") {
- wx.hideLoading();
- }
- console.log(url + ' 返回的data:', com.data);
- }
- })
- }
- const formatNumber = n => {
- n = n.toString()
- return n[1] ? n : '0' + n
- }
-
- module.exports = {
- formatTime: formatTime,
- request: request
- }



















