一、为什么需要用户登录
从产品角度方式出发:
- 电商应用:用户登录后加入购物车、购买商品、收藏商品
- 音乐应用:用户登录后收藏歌曲、评论歌曲等
二、如何识别同一个小程序用户身份
每个微信用户有唯一一个openid,openid可标识微信用户。
在用户进行登录小程序时,可获取到该微信用户的openid作为唯一标识。
那么我们如何获取openid呢?
2-1、openid获取流程(小程序登录流程)
我们先来看官方文档里的小程序登录时序图:
1、我们需要在小程序中拿到一个临时的code(通过wx.login(),wx.login()是不需要用户授权的)
- 如果拿到的不是临时的而是一直有效的code,就可以一直去换取openid是不安全的,所以拿到的是临时的code
2、将临时的code传递给自己的(公司的)服务器
3、服务器拿到小程序发送的code后,向微信服务器发送网络请求并携带appid、appsecret、code
- 调取的接口为: auth.code2Session
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去微信服务器去换取手机号:
- code的有效期为5min
- 官方文档:phonenumber.getPhoneNumber
- 该接口需要服务器端去调用