小程序—用户登录流程解析

605 阅读6分钟

一、为什么需要用户登录

从产品角度方式出发:

  • 电商应用:用户登录后加入购物车、购买商品、收藏商品
  • 音乐应用:用户登录后收藏歌曲、评论歌曲等

二、如何识别同一个小程序用户身份

每个微信用户有唯一一个openid,openid可标识微信用户。

在用户进行登录小程序时,可获取到该微信用户的openid作为唯一标识。

那么我们如何获取openid呢?

2-1、openid获取流程(小程序登录流程)

我们先来看官方文档里的小程序登录时序图:

1、我们需要在小程序中拿到一个临时的code(通过wx.login(),wx.login()是不需要用户授权的

  • 如果拿到的不是临时的而是一直有效的code,就可以一直去换取openid是不安全的,所以拿到的是临时的code

2、将临时的code传递给自己的(公司的)服务器

3、服务器拿到小程序发送的code后,向微信服务器发送网络请求并携带appid、appsecret、code

4、微信服务器拿到appid、appsecret、code后会发送给服务器openid与session_key

  • 如果想要进行手机号解密或访问微信服务器其他东西时,是需要access_token的
  • 这个session_key就是用来换取access_token的

5、拿到openid后,短时间内用户再次登录小程序时是不需要再向微信服务器获取openid的(一直向微信服务器换取openid是不合适的,而且微信服务器会有一定限制),所以可以将拿到的openid与session_key与其他信息在自己的服务器侧生成token

6、将token返回给小程序端,小程序端便可将token存入storage中

7、小程序端拿到自己服务器的token后,接下来用户做操作时,是将此token发送给服务器的

  • 可先判断本地storage中有无token,没有则进行登录登录
  • 有token,则判断token有无过期,过期了则进行重新登录

8、自己的服务器拿到token后便可以解析token获取出来openid、session_key以及其他信息,便可进行数据库操作并记录用户操作信息了~

2-2、代码演示

2-2-1、通过wx.login()获取code

  wx.login({
    timeout: 1000,
    success: res => {
      console.log(res.code)
    },
    fail: err => {
      console.log(err)
    }
  })

由于在获取到code后,还需要将code发送给服务器让服务器通过微信服务器获取openid等一系列操作,这样callback拿到结果的方式不太友好,容易产生回调地狱,所以我们可以将此方法封装一下:

export function getLoginCode() {
  return new Promise((resolve, reject) => {
    wx.login({
      timeout: 1000,
      success: res => {
        resolve(res.code)
      },
      fail: err => {
        reject(err)
      }
    })
  })
}

此时便可以通过封装的Promise形式的方法来获取code了:

2-2-2、向服务器传递code并获取自定义登录态(token)

  loginAction: async function() {
    const code = await getLoginCode()
    const { token } = await sendCodeToToken(code)
    wx.setStorageSync('token', token)
  }

在拿到token后,可将token保存在storage中方便操作时携带

2-2-3、优化登录逻辑

1、在登录之前,最好先判断一下storage中有无token

2、如果有,则判断token有无过期,在判断token有无过期时有两种方式:

  • 一种是在前端请求接口从header中携带过去token后,后端判断token过期后会直接响应token过期了,前端接收到token过期响应后去跳转登录的
  • 另一种是后端提供一个校验token有无过期的接口去专门验证token有无过期

3、我们最好也要判断一下session_key有无过期,因为过期后后续再进行使用微信服务器提供的其他服务时,是无法通过session_key拿到access_token的

  • 判断session_key有无过期可通过wx.checkSession()

封装wx.checkSession()请求:

export function checkSessionKey() {
  return new Promise((resolve, reject) => {
    wx.checkSession({
      success: () => {
        resolve(true)
      },
      fail: () => {
        resolve(false)
      }
    })
  })
}

三、如何获取用户信息

微信为我们提供了获取用户信息的接口:

  • wx.getUserProfile
  • 其中需要传入desc(必填)
  • 成功结果通过success回调告知
  • 失败结果通过fail回调告知
  • 需要注意的是:获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo(这是由于之前都是直接在onLanuch直接调取,会导致一打开小程序就会提示授权弹窗,而用户都不知道小程序是干啥的呢就弹窗授权,大部分都会选择拒绝授权,这样小程序就拿不到用户的相关信息了)
  • 相关官方文档:wx.getUserProfile

3-1、封装获取用户信息方法

export function getUserInfo () {
  return new Promise((resolve, reject) => {
    wx.getUserProfile({
      desc: '你好',
      success: (res) => {
        resolve(res)
      },
      fail: (err) => {
        reject(err)
      }
    })
  })
}

3-2、通过点击事件发起调取方法

在页面的wxml中:

<button open-type="getUserInfo" bindtap="handleGetUser">获取用户信息</button>

在页面的js中:

import { getUserInfo } from '../../service/api_login'

Page({
  handleGetUser: async function(event) {
    const userInfo = await getUserInfo()
    console.log(userInfo)
  }
})

此时点击获取用户信息的按钮时便可弹出授权弹窗,点击允许后便可获取到用户信息了~

四、用户身份多平台共享

openid可作为同一个用户在小程序中多次登录的唯一标识

unionid也是一个唯一标识,其可作为用户在多个平台授权时的唯一标识

  • 往往同一产品不只有小程序端,也会有公众号端、h5端(h5端的第三方登录可以是微信登录)等
  • 如果用户是在小程序端做了一些操作(比如收藏、点赞、评论等等),也希望在公众号端看到自己所操作的内容,那么在多端共享数据时,如何识别是否是同一个用户此时就要通过unionid了,而openid是做不到的(openid仅仅是在小程序中是唯一的)
  • 但是如果是PC端,没有提供微信登录就无法拿到用户的unionid了,怎么办?
    • 往往在产品设计的时候会让用户在小程序登录时去绑定手机/邮箱
    • 这样在PC端去用手机/邮箱登录时便可去通过用户的手机/邮箱信息查到关联的unionid了,这样便可标识同一用户进而在PC端去拿到小程序中所操作的数据了~

4-1、手机号获取

官方文档说明:获取手机号

页面的wxml中:

<button open-type="getPhoneNumber" bindgetphonenumber="handleGetPhoneNumber">获取手机号码</button>

页面的js中:

Page({
  handleGetPhoneNumber: function(event) {
    console.log(event.detail.code)
  }
})

!注意: 目前该接口针对非个人开发者

获取的为动态的code,需要拿着这个code去微信服务器去换取手机号: