小程序相关

实现效果:

 

微信开发着工具 登录获取手机号 github app微信登录获取手机号_html

 

1.开发工具uniapp

2.功能模块

  ① 登录模块(微信登录,授权获取昵称,头像,地区等,授权获取手机号,解密手机号)

  ② UI模块 (uview,vant)

  ③ 请求模块 (axios封装) 

  ④ 问题汇总

3.功能拆解(附代码)

  ① 微信登录:文档(https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html)

   步骤:

      <1> 通过微信官方提供的登录api(wx.login)获取code,用code当参数请求后台接口获取openid,以此作为登录凭证

      <2> 分段代码:

        

wx.login({
    success(res) {
        if (res.code) {
            //向后台发起网络请求
            wx.request({
                url: '后台提供的接口地址',
                data: {
                    code: res.code
                },
                success(res) {
                    console.log("获取到的openid是:", res)
                }
            })
        } else {
            console.log('登录失败!' + res.errMsg)
        }
    }
})

  ② 授权获取昵称,头像,地区:文档(https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html)

   步骤:

      <1> 页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用

      <2> 分段代码:

        

wx.getUserProfile({
    lang: 'zh_CN',
    desc: '用户登录',
    success: (res) => {
        console.log("用户允许授权后获得的信息为:", res)
    },
    fail: (err) => {
        console.log("用户拒绝授权")
    }
})

  ③ 授权获取手机号及解密,文档(https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html)

    步骤:

      <1> 将 button 组件 open-type 的值设置为 getPhoneNumber

      <2> 用户同意后,通过 bindgetphonenumber 事件回调获取到微信服务器返回的加密数据

      <3> 获取session_key

      <4> 向后台发送参数解密手机号

      <5> 分段代码:

// html代码:

// 原生微信小程序写法:
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>

// uniapp写法:
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号码</button>

// js代码:

// 获取手机号:

getPhoneNumber(e) {
  if (e.detail.errMsg !== "getPhoneNumber:ok") return; // 如果用户不同意授权则返回并结束
  console.log(e.detail.errMsg)
  console.log(e.detail.iv)
  console.log(e.detail.encryptedData)
}

// 检验登录是否过期:

uni.checkSession({
    success(res) {
        console.log("登录未过期,进行下一步操作")
    },
    fail() {
        console.log("登录已过期,请重新登录")
    }
})

// 获取session_key,以此作为参数进行解密手机号

wx.request({
    url: "https://api.weixin.qq.com/sns/jscode2session",
    data: {
        'appid': "小程序的appid",
        'secret': "小程序密钥",
        'js_code': "登录时获取到的code",
        'grant_type': "authorization_code" // 默认填写authorization_code
    },
    method: 'GET',
    header: {
        'content-type': 'application/json'
    },
    success: function(res) {
        console.log("成功获取到session_key", res)
    },
    fail(err) {
        console.log("获取session_key失败", err)
    }
})

// 解密手机号

wx.request({
    url: '后台提供的接口地址',
    data: {
        'encryptedData': e.detail.encryptedData,
        'iv': e.detail.iv,
        'session_key': "上一步获取到的session_key"
    },
    method: 'GET',
    header: {
        'content-type': 'application/json'
    },
    success: function(data) {
        console.log("获取到的手机号是", data)
    },
    fail: function(err) {
        console.log(err)
    }
})

  ④ 微信登录流程的完整代码:

    

<template>
  <!-- #ifdef MP-WEIXIN -->
  <view v-if="!isCanUse">
    <view>
      <view class='header'>
        <image src='你的网站logo等等'></image>
      </view>
      <view class='content'>
        <view>申请获取以下权限</view>
        <text>获得你的公开信息(昵称,头像、地区等)</text>
      </view>
      <button v-if="!flag" type="primary" class='btn' withCredentials="true" lang="zh_CN" open-type="getUserInfo" @tap="wxLogin">
        授权登录
      </button>
      <button v-else type="primary" class='btn' open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">获取手机号码</button>
    </view>
  </view>
  <!-- #endif -->
</template>
<script>
export default {
  data() {
    return {
      SessionKey: '',
      OpenId: '',
      code: '',
      isCanUse: uni.getStorageSync('isCanUse'), //默认为true
      token: '',
      userInfo: {
        nickName: null,
        avatarUrl: null,
      },
      flag: false,
      toWeb: false,
      webSrc: 'http://localhost:8080/#/?token=' + uni.getStorageSync('token'),
    }
  },
  onLoad() {
    if (uni.getStorageSync('isCanUse') == '1') {
      console.log('已经授权登录过了,请直接跳转')
    } else {
      console.log('未授权登录,请点击登录')
    }
  },
  methods: {
    wxLogin(e) {
      let p1 = this.wxSilentLogin() // 获取code
      let p2 = this.wxGetUserProfile() // 获取用户信息
      p1.then((code) => {
        return code
      })
        .then((code) => {
          this.code = code
          return new Promise((resolve, reject) => {
            p2.then((res) => {
              resolve({
                code,
                iv: res.iv,
                encryptedData: res.encryptedData,
              })
            }).catch((err) => {
              reject(err)
            })
          })
        })
        .then((res) => {
          let _this = this
          // 请求服务器
          wx.request({
            url: '后台提供的接口',
            method: 'get',
            data: {
              code: res.code,
              encrypted_data: res.encryptedData,
              iv: res.iv,
            },
            header: {
              'content-type': 'application/json', // 默认值
            },
            success(res) {
              uni.setStorageSync('token', res.data.data)
              _this.token = res.data.data
              console.log('获取token', _this.token)
            },
          })
        })
        .catch((err) => {
          console.log(err)
        })
    },
    wxGetUserProfile: function () {
      // 获取头像昵称等
      let _this = this
      return new Promise((resolve, reject) => {
        wx.getUserProfile({
          lang: 'zh_CN',
          desc: '用户登录',
          success: (res) => {
            resolve(res)
            console.log('获取到的用户信息', res.userInfo)
            _this.userInfo.nickName = res.userInfo.nickName
            _this.userInfo.avatarUrl = res.userInfo.avatarUrl
            uni.setStorageSync('isCanUse', '1')
            _this.flag = true
            // _this.updateUserInfo();
          },
          // 失败回调
          fail: (err) => {
            reject(err)
            console.log('选择了拒绝')
          },
        })
      })
    },
    wxSilentLogin: function () {
      // 获取code
      return new Promise((resolve, reject) => {
        wx.login({
          success(res) {
            resolve(res.code)
            console.log('获取得到的loginres', res)
          },
          fail(err) {
            reject(err)
          },
        })
      })
    },
    getPhoneNumber: function (e) {
      var self = this
      if (e.detail.errMsg !== 'getPhoneNumber:ok') return
      wx.showLoading()
      uni.checkSession({
        success(res) {
          if (self.code) {
            //    2.访问登录凭证校验接口获取session_key
            wx.request({
              url: 'https://api.weixin.qq.com/sns/jscode2session',
              data: {
                appid: '小程序appid',
                secret: '小程序密钥',
                js_code: self.code,
                grant_type: 'authorization_code',
              },
              method: 'GET',
              header: {
                'content-type': 'application/json',
              },
              success: function (data) {
                console.log('获取到session_key啦', data)
                if (data.statusCode == 200) {
                  //3. 解密
                  wx.request({
                    url: '后台提供的接口',
                    data: {
                      encryptedData: e.detail.encryptedData,
                      iv: e.detail.iv,
                      sessionKey: data.data.session_key,
                    },
                    method: 'GET',
                    header: {
                      'content-type': 'application/json',
                    },
                    success: function (data) {
                      wx.hideLoading()
                      console.log('获取到的手机号是', data.data.phoneNumber)
                    },
                    fail: function (err) {
                      console.log(err)
                    },
                  })
                }
              },
              fail: function (err) {
                console.log(err)
              },
            })
          } else {
            wx.showToast({
              icon: 'none',
              title: '授权失败,请重新授权',
            })
            self.flag = false
          }
        },
        fail() {
          wx.showToast({
            icon: 'none',
            title: '登录过期,请重新登录',
          })
        },
      })
    },
    updateUserInfo: function () {
      return new Promise((resolve, reject) => {
        console.log('发送给后台的用户信息', this.userInfo)
        wx.request({
          url: '后台提供的接口',
          method: 'POST',
          data: {
            openId: '',
            password: '',
            telePhone: '',
            tenantId: 0,
            username: '',
          },
          header: {
            'content-type': 'application/json', // 默认值
          },
          success(res) {
            console.log(333, res.data)
          },
        })
        wx.login({
          success(res) {
            resolve(res.code)
          },
          fail(err) {
            reject(err)
          },
        })
      })
    },
  },
}
</script>

<style>
.header {
  margin: 90rpx 0 90rpx 50rpx;
  border-bottom: 1px solid #ccc;
  text-align: center;
  width: 650rpx;
  height: 300rpx;
  line-height: 450rpx;
}

.header image {
  width: 240rpx;
  height: 240rpx;
  border-radius: 50%;
}

.content {
  margin-left: 50rpx;
  margin-bottom: 90rpx;
}

.content text {
  display: block;
  color: #9d9d9d;
  margin-top: 40rpx;
}

.btn {
  background: #1890FF !important;
  line-height: 80rpx !important;
  border-radius: 80rpx !important;
  margin: 70rpx 50rpx !important;
  font-size: 35rpx !important;
}
</style>

 

  

注:1. background: url 无法使用静态资源,可以使用线上资源或者数据流(base64等),在线图片库

  2.分包:文件资源过大时,可使用分包加载 ()