微信小程序打夯之旅(一):登录流程

2,255 阅读5分钟

基础术语

1. code: 调用wx.login后返回的临时登录凭证,可请求微信服务器换取openId和session_key
2. openId:用户唯一标识,同一用户在不同的应用中不一致
3. session_key:对用户数据进行加密签名的密钥
4. appId:小程序唯一标识,申请小程序成功后获得分配
5. unionId:用户在开放平台的唯一标识符,同一用户在同一账号下的所有应用中一致

UnionID 机制说明

如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

UnionID获取途径

UnionID 获取途径:绑定了开发者帐号的小程序,可以通过下面的途径获取 UnionID

  • 调用接口 wx.getUserInfo,从解密数据中获取 UnionID。注意本接口需要用户授权,请开发者妥善处理用户拒绝授权后的情况。

  • 如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号。开发者可以直接通过 wx.login + code2Session 获取到该用户 UnionID,无须用户再次授权。

  • 如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用。开发者也可以直接通过wx.login + code2Session 获取到该用户 UnionID,无须用户再次授权。

  • 用户在小程序(暂不支持小游戏)中支付完成后,开发者可以直接通过 getPaidUnionId 接口获取该用户的 UnionID,无需用户授权。注意:本接口仅在用户支付完成后的5分钟内有效,请开发者妥善处理。

  • 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号,可在云函数中通过 cloud.getWXContext 获取 UnionID

  • 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用,也可在云函数中通过 cloud.getWXContext 获取 UnionID

小程序登录流程示意图

1. 通过wx.login() 获取code
2. 将code发送给后端,后端请求微信服务器code2Session接口换取openId和sessionKey
3. 将openId与唯一登录态绑定并把登录态返回给用户

image

需要授权的信息

部分接口需要经过用户授权同意才能调用,如用户信息、地理位置、地址等等,需要注意的是,如果用户已经拒绝了授权,就不会再出现授权弹窗,此时应该引导用户前往设置界面打开授权,开发者可以调用 wx.openSetting 打开设置界面,引导用户开启授权。

提前发起授权

除了 userInfo,其他的授权信息都可以使用 wx.authorize 提前发起授权,而 userInfo 只能通过 button 触发。

// 点击后将出发弹窗,点击允许或拒绝将调用回调
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">

getUserInfo(e) {
  // 用户拒绝授权
  if (e.detail.errMsg == 'getUserInfo:fail auth deny'){
    this.showError('您还没有授权微信登录');
  } else {
    // 获取用户信息成功
    this.weixinLoginNew();
  }
}

e.detail 数据结构说明(跳过吧)

  • encryptedData: 加密后的用户敏感信息,如openId和unionId
  • iv:加密算法的初始向量,后端通过iv、encryptedData及解密算法进行解密获得openId
  • signature:数据签名,signature = sha1( rawData + session_key ),开发者将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 即可校验数据的完整性。
  • userInfo:用户非敏感信息,包含头像、昵称、性别等

需要授权的信息列表

scope 对应接口 描述
scope.userInfo wx.getUserInfo 用户信息
scope.userLocation wx.getLocation, wx.chooseLocation 地理位置
scope.address wx.chooseAddress 通讯地址
scope.invoiceTitle wx.chooseInvoiceTitle 发票抬头
scope.invoice wx.chooseInvoice 获取发票
scope.werun wx.getWeRunData 微信运动步数
scope.record wx.startRecord 录音功能
scope.writePhotosAlbum wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum 保存到相册
scope.camera <camera />组件 摄像头

获取手机号

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

Page({
  getPhoneNumber(e) {
    // 揭秘后JSON结构:{phoneNumber(有区号), purePhoneNumber, countryCode }
    console.log(e.detail.encryptedData)
  }
})

案例(封装了一个微信登录组件)

1. 查看用户设置信息验证是否授权过

ready() {
  wx.getSetting({
    success: (res) => {
      if (res.authSetting['scope.userInfo']) {
        // 已经授权,可以直接调用 wx.getUserInfo 获取头像昵称
        this.setData({ isAuthorization : true});
      }
    }
  });
}

2. 页面结构 如果已经授权过,则可以直接调用 wx.getUserInfo 无需按钮授权,slot 中可以放置任何元素,用以描述登录按钮。

<view class="login-wrap" catchtap="weixinLogin">
  <slot></slot>
  <button wx:if="{{ !isAuthorization }}" open-type="getUserInfo" bindgetuserinfo="getUserInfo" class="wx-btn" size="min">
  </button>
</view>
// 数据
data: {
  isAuthorization: false,     // 是否已经验证过
  canIUse: wx.canIUse('button.open-type.getUserInfo'),
},
/* 样式 */
<style lang="scss">
.login-wrap {
  position: relative;
}
.wx-btn {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0rpx;
  top: 0rpx;
  z-index: 100;
  border-radius:0rpx;
  background:none;
  margin:0rpx;
  padding:0rpx;
}

.wx-btn:after {
  border: none;
}
</style>

3.处理点击行为 如果用户已经授权,则会触发 weixinLogin 事件。

weixinLogin (e) {
  if (!this.data.isAuthorization) return;
  // 通过 wx.login() 完成微信登录
  // 通过 wx.getUserInfo() 获取用户信息
},

如果用户未授权过,则会触发 getUserInfo 事件。

// 微信登录按钮触发getUserInfo
getUserInfo(e) {
  if (!this.data.canIUse){
    this.showError('请升级微信到最新版本');
    return;
  }
  if (e.detail.errMsg == 'getUserInfo:fail auth deny'){
    this.showError('您还没有授权微信登录');
  } else{
    wx.showLoading({ title: 'loading', mask: true });
    // 通过 wx.login() 完成微信登录
    // 通过 wx.getUserInfo() 获取用户信息
  }
}