微信小程序 获取用户手机号

参考链接:
(1)微信小程序开发用户授权登录
https://www.cnblogs.com/dashucoding/p/9917371.html
(2)微信小程序如何通过用户授权获取手机号(getPhoneNumber)
https://www.jb51.net/article/179007.htm
获取手机号 | 微信开放文档
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
(3)微信小程序使用wx.login()获取用户的openid和session_key(示例后端使用Thinkphp)https://blog.csdn.net/qq15577969/article/details/102699215

在这里插入图片描述
在这里插入图片描述
在开发微信小程序过程中,需要绑定微信用户的信息到数据库里,那么就需要获得用户的唯一标识openid,而微信为了安全,禁止小程序直接访问https://api.weixin.qq.com 的接口,因此不能直接拿到用户的openid。

解决方案:

  1. 先通过wx.login获取一个临时凭证code
    wx.login(OBJECT)
    调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)。用户数据的加解密通讯需要依赖会话密钥完成。

  2. 然后我们拿这个code去自己的服务器换取用户openid和session_key(code 换取openid和session_key)
    这是一个 HTTPS 接口,开发者服务器使用登录凭证 code 获取 session_key 和 openid。其中 session_key 是对用户数据进行加密签名的密钥。为了自身应用安全,session_key 不应该在网络上传输。

一、前端微信小程序,后端Thinkphp

微信小程序前端代码(app.js)

//app.js
App({
  onLaunch: function() {
    // 展示本地存储能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)
    /*
    * 获取用户openid
    * 示例说明:微信为了安全,禁止小程序访问https://api.weixin.qq.com 的接口,因此不能直接拿到用户的openid
    * 解决方案:
    * 1、先通过wx.login获取一个临时凭证code
    * 2、然后我们拿这个code去自己的服务器换取用户openid
    */
    var that=this;
    wx.login({
      success: function (res) {
        var code = res.code;//发送给服务器的code
        wx.getUserInfo({
          success: function (res) {
            var userNick = res.userInfo.nickName; //用户昵称
            var avataUrl = res.userInfo.avatarUrl;//用户头像地址
            var gender = res.userInfo.gender;     //用户性别
            if (code) {
              wx.request({
                url: 'https://后端网址/getOpenid.html',
                data: {
                  code: code,
                  nick: userNick,
                  avaurl: avataUrl,
                  sex: gender,
                },
                header: {
                  'content-type': 'application/json'
                },
                success: function (res) {
                  console.log('获取到的用户openid为:' + res.data.openid);
                  //可以把openid保存到本地缓存,方便以后调用
                  wx.setStorageSync('openid', res.data.openid);
                }
              })
            }
            else {
              console.log("获取用户登录态失败!");
            }
          }
        })
      },
      fail: function (error) {
        console.log('login failed ' + error);
      }
    })    
  },
  /**
   * 全局属性
   */
  globalData: {
    userInfo: null
  }
})

后端Thinkphp代码

public function getOpenid(){
		
 if(!isset($_GET['code'])||!isset($_GET['nick'])||!isset($_GET['avaurl'])||!isset($_GET['sex'])){
            header("Content-type: text/html; charset=utf-8"); 
            echo '参数错误.';
            exit;
 }
		//微信小程序appid
		$appid='小程序的APPID';
		//微信小程序secret
                $secret='小程序的SECRET';
		$code = $_GET['code'];		//小程序传来的code值
		$nick = $_GET['nick'];		//小程序传来的用户昵称
		$imgUrl = $_GET['avaurl'];	//小程序传来的用户头像地址
		$sex = $_GET['sex'];		//小程序传来的用户性别
		$url = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$appid.'&secret='.$secret.'&js_code=' . $code . '&grant_type=authorization_code';
		$info = file_get_contents($url);//发送HTTPs请求并获取返回的数据,推荐使用curl
		$json = json_decode($info);//对json数据解码
		$arr = get_object_vars($json);
		$openid = $arr['openid'];
		$session_key = $arr['session_key'];
		echo json_encode($arr);
	}

二、获取手机号

wxml文件

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>

JS内getPhoneNumbe组件函数(该事件中最重要的就是在wx.login登录后发起接口请求),这里需要配置参数来给接口:
这些是必不可少的参数,这些齐备才能算一个合法的请求。

appid: "你的小程序APPID",
secret: "你的小程序appsecret",
code: res.code,
encryptedData: telObj,
iv: ivObj

js文件

//通过绑定手机号登录
  getPhoneNumber: function (e) {
   var ivObj = e.detail.iv
   var telObj = e.detail.encryptedData
   var codeObj = "";
   var that = this;
   //------执行Login---------
   wx.login({
    success: res => {
     console.log('code转换', res.code);
   //用code传给服务器调换session_key
     wx.request({
      url: 'https://你的接口文件路径', //接口地址
      data: {
       appid: "你的小程序APPID",
       secret: "你的小程序appsecret",
       code: res.code,
       encryptedData: telObj,
       iv: ivObj
      },
      success: function (res) {
       phoneObj = res.data.phoneNumber;
       console.log("手机号=", phoneObj)
       wx.setStorage({  //存储数据并准备发送给下一页使用
        key: "phoneObj",
        data: res.data.phoneNumber,
       })
      }
     })
     //-----------------是否授权,授权通过进入主页面,授权拒绝则停留在登陆界面
     if (e.detail.errMsg == 'getPhoneNumber:user deny') { //用户点击拒绝
      wx.navigateTo({
       url: '../index/index',
      })
     } else { //允许授权执行跳转
      wx.navigateTo({
       url: '../test/test',
      })
     }
    }
   });
},

在这里插入图片描述
点击"拒绝",开发者能捕捉到该事件 ,此时getPhoneNumber 函数返回 e.detail.errMsg 为 getPhoneNumber:user deny

三、后台openid和session_key得手机号

用wx.login获取登录凭证code

<!--pages/user/index.wxml-->
<view hidden='{{boolean}}'>
	<view wx:if="{{isLogin == 1}}">
		<!-- 个人信息 -->
		<view class='infomation'>
			<!-- 基本信息 -->
			<view class="gameTitle">
				<navigator hover-class="none" href=""><image src="{{dataList.head_photo}}"></image></navigator>
				<view>
					<view class="gameName"><navigator hover-class="none" href="">{{dataList.username}}</navigator></view>
					<view class="gameSummary" wx:if="{{dataList.title == ''}}"><navigator hover-class="none" href="">这个玩家很懒,什么也没留下</navigator></view>
					<view class="gameSummary" wx:if="{{dataList.title != ''}}"><navigator hover-class="none" href="">{{dataList.title}}</navigator></view>
				</view>
			</view>
			
		</view>
		<!-- “我的”列表 -->
		<view class='myList'>
			<view class='list'>
			</view>
		</view> 
	</view>
	<view wx:if="{{isLogin == 2}}">
		<view class='bgBox'>
			
		</view>
		<view class="unLogin">

		</view>
	</view>
</view>

wx.checkSession 校验登陆态

//原型:检测当前用户登录态是否有效
wx.checkSession({
  success: function(){
    //session 未过期,并且在本生命周期一直有效
  },
  fail: function(){
    //登录态过期
    wx.login() //重新登录
    ....
  }
})
  • success :接口调用成功,session_key未过期;
  • fail :接口调用失败,session_key已过期;
  1. 小程序端 wx.login 获取code 并 wx.request 提交 code 给己方服务器
  2. 服务器 提交Appid + appSecret + code 到微信方服务器 获取 session_key & openid
  3. 服务器 根据 session_key & openid 生成 3rd_session(微信方提出的基于安全性的考虑,建议开发者不要将openid等关键性信息进行数据传输) 并返回 3rd_session 到小程序端
  4. 小程序端 wx.setStorage 存储 3rd_session 在后续用户操作需要凭证时 附带该参数
  5. 小程序端 wx.getUserInfo 获取用户信息 + wx.getStorage 获取 3rd_session 数据后,一并 wx.request 提交给己方服务器
  6. 服务器 SQL 用户数据信息更新
//用户登陆
function userLogin() {
  wx.checkSession({
    success: function () {
      //存在登陆态
    },
    fail: function () {
      //不存在登陆态
      onLogin()
    }
  })
}
 
function onLogin() {
  wx.login({
    success: function (res) {
      if (res.code) {
        //发起网络请求
        wx.request({
          url: 'Our Server ApiUrl',
          data: {
            code: res.code
          },
          success: function (res) {
            const self = this
            if (逻辑成功) {
              //获取到用户凭证 存儲 3rd_session 
              var json = JSON.parse(res.data.Data)
              wx.setStorage({
                key: "third_Session", 
                data: json.third_Session
              })
              getUserInfo()
            }
            else {
 
            }
          },
          fail: function (res) {
 
          }
        })
      }
    },
    fail: function (res) {
  
    }
  })
 
}
 
function getUserInfo() {
  wx.getUserInfo({
    success: function (res) {
      var userInfo = res.userInfo
      userInfoSetInSQL(userInfo)
    },
    fail: function () {
      userAccess()
    }
  })
}
 
function userInfoSetInSQL(userInfo) {
  wx.getStorage({
    key: 'third_Session',
    success: function (res) {
      wx.request({
        url: 'Our Server ApiUrl',
        data: {
          third_Session: res.data,
          nickName: userInfo.nickName,
          avatarUrl: userInfo.avatarUrl,
          gender: userInfo.gender,
          province: userInfo.province,
          city: userInfo.city,
          country: userInfo.country
        },
        success: function (res) {
          if (逻辑成功) {
            //SQL更新用户数据成功
          }
          else {
            //SQL更新用户数据失败
          }
        }
      })
    }
  })
}

第三方服务器和微信服务器:
注意:session_key是微信服务器生成的针对用户数据进行加密签名的密钥,不应该进行传输到客户端.

生成3rd_session
用于第三方服务器和小程序之间做登录态校验.为了保证安全性,3rd_session应该长度够长,一定有效时间, session_key + openid, key, 为 value, 写入到session存储.

3rd_session写入storage:
后续用户进入小程序,先从storage读取3rd_session
根据请求,在session存储中查找合法的session_key和openid

App({
  onLaunch: function() {
    wx.login({
      success: function(res) {
        var code = res.code;
        if (code) {
          console.log('获取用户登录凭证:' + code);
        } else {
          console.log('获取用户登录态失败:' + res.errMsg);
        }
      }
    });
  }
})

唯一标识(openid)和会话密钥(session_key)
在这里插入图片描述
服务端处理逻辑

wx.checkSession({
    success:function(res){
      //session_key未过期
    },
    fail:(res=>{
      // session_key已过期
      // 进行登录操作
      wx.login({
        success: function(res) {
          const url = '接口地址'   //本次项目中是从后台获取session_key的接口,可能流程不同,会有相应的变化
          const data = {
            //你要传的数据
          }
          wepy.request({
            url: url,
            method: 'POST',
            data: data,
          }).then(res=>{
            if(res.data.code == 0){
              //拿到的openid和session_key存到缓存中

              //调用换取用户id接口[需求不同,可能接口会有相应的变化]
              const url = '获取用户id的接口'
              const data = {'要传的数据'}
              wepy.request({
                url: url,
                method: 'POST',
                data: data,
              }).then((res)=>{
                //该接口设计返回的参数包括换取的用户ID和返回的用户的微信中信息,也就是通过button获取的那个userInfo[我们为了后续的处理,所以后台这块返回用户信息,如果用户还未登录,用户信息,返回是空,反之则有值]
                //存储用户ID
                wx.setStorage({
                  key:'userId',
                  data:'获取到的用户ID'
                })
                //存储用户信息[userInfo]
                wx.setStorage({
                  key:'userInfo',
                  data:'获取到的用户信息'
                })
              })
            }
          })
        }
      });
    })
  })
onShow(){
    //从缓存中获取session_key
    let skey = wx.getStorageSync('session_key');
    if (!skey) {
      //如果session_key不存在,再次执行登录
      wx.login({
        //该处登录同app.wpy[流程一样]
      });
    }else{
      // session_key存在
    }
  }
  //我们假设这个页面需要获取用户的信息,首先给一个button[open-type设置为getUserInfo],使用这个拿到用户的信息,
  getUserInfo(e){
      this.userInfo = e.detail.userInfo;  //e.detail.userInfo携带的就是用户的个人信息[包括头像、昵称等]
      if(e.detail.userInfo){
        wx.showToast({
          title: '授权成功',
          icon: 'success',
          duration: 1500
        })
        //这里做这样的处理,是因为需求需要点击购物车按钮跳转订单待支付页,在没有获取到用户信息之前,跳转购物车的按钮隐藏,获取用户信息按钮显示,反之则返
        this.button = 'none';   //获取用户信息button
        this.myMenu = 'block';  //跳转待支付订单页
        //更新缓存中的用户信息
        wx.setStorage({
          key:'userInfo',
          data:this.userInfo
        })
      }else if(e.detail.errMsg == 'getUserInfo:fail auth deny'){
        wx.showModal({
          title: '提示',
          content: '若不授权微信登录,则无法使用小程序。点击"授权"按钮并允许使用"用户信息"方可正常使用。',
          showCancel:false,
          confirmText:'授权',
          success:(res=>{
            wx.openSetting({
              success: (res) => {
              }
            })
          })
        })
      }
    }

在这里插入图片描述
在这里插入图片描述
数字签名校验
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
在这里插入图片描述
对称解密的目标密文为 Base64_Decode(encryptedData)。
对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

signature = sha1( rawData + session_key )

//最终供外面调用的方法
function login(){
    console.log('logining..........');
    //调用登录接口
    wx.login({
        success: function (e) {
            console.log('wxlogin successd........');
            var code = e.code;
            wx.getUserInfo({
                success: function (res) {
                    console.log('wxgetUserInfo successd........');
                    var encryptedData = encodeURIComponent(res.encryptedData);
                    thirdLogin(code,encryptedData,res.iv);//调用服务器api
                }
            })
        }
    });
}

function  thirdLogin(code,encryptedData,iv){
    var url = "eeee/xxx/login/ttttt";
    var params = new Object();
    params.code = code;
    params.encryptedData = encryptedData;
    params.iv =iv;

    buildRequest(new Object(),url,params,{
        onPre: function(page){},
        onSuccess:function (data){
            console.log('my  login successd........');
            console.log(data);
            getApp().globalData.session_id = data.session_id;
            getApp().globalData.uid = data.uid;
            getApp().globalData.isLogin = true;
        },
        onError : function(msgCanShow,code,hiddenMsg){
        }
    }).send();
}
  • 1
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值