这篇文章主要介绍了小程序:授权、登录、session_key、unionID、openID等的详解,主要分为两个部分来介绍,第一部分是简单的整理说明,以求理清关系。第二部分授权登录的逻辑参考了多个小程序,希望能找到最优的模式,并会配合代码详细讲解整个流程。
目录
一、API详解
1.登录
2.授权
3.用户信息
4.部分字段解释
二、登录授权流程
1.模式概览
2.主动登录
3.调用接口
4.弹窗提示
通过wx.login
拿到code
给后台,接口返回token
、openID
等参数。有了这些参数我们就可以直接请求那些不需要用户操作便可以读取的接口(比如:列表、详情、视频播放等等);
①wx.login(OBJECT)
调用接口wx.login() 获取临时登录凭证(code),调用成功后能拿到用户登录凭证(有效期五分钟)。开发者需要在开发者服务器(自己的服务器)后台调用 api,使用 code 换取 openID 和 session_key 等信息。
wx.login({
success: function(res) {
console.log(res)
//{errMsg: "login:ok", code: "081ckzKc1nYWou0wkHLc19pDKc1ckzKR"}
if (res.code) {
// 发起网络请求,用于用户登录
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
②wx.checkSession(OBJECT)
校验用户当前session_key是否有效。
wx.checkSession({
success: function(){
//session_key 未过期,并且在本生命周期一直有效
},
fail: function(){
// session_key 已经失效,需要重新执行登录流程
wx.login() //重新登录
}
})
也就是说,每次打开应用时,检测微信session_key是否过期,如果没过期什么都不用做,如果过期了重新登录获取微信session_key。然后获取开发服务器的session,从而达成正真意义上的登录。
当小程序需要用户操作(比如:关注、评论、添加购物车、地理位置、个人中心等等),就需要用户先授权。
①wx.authorize(OBJECT)
提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。
(1)如果用户已授权,可以直接调用接口;
(2)如果用户未授权,会弹出授权框询问用户:
a.拒绝授权:关闭授权框,用户操作无效(如关注,无法触发关注的http请求,保持原状);
b.接收授权:将用户信息通过token
发送给后台,并主动请求用户操作(如关注,接收授权后触发关注的http请求,提示关注成功)。
scope 为 "scope.userInfo" 时,无法弹出授权窗口。需要用button的方式,文章下面会讲。(小程序后面升级的)
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.record']) {
wx.authorize({
scope: 'scope.record',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
wx.startRecord()
}
})
}
}
})
①wx.getUserInfo(OBJECT)
注意:此接口有调整,使用该接口将不再出现授权弹窗,请使用下面代码来引导用户主动进行授权操作。
请升级微信版本
//js
Page({
data: {
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
onLoad: function() {
// 查看是否授权
wx.getSetting({
success: function(res){
console.log(res)
// {userInfo: ,rawData: ,signature ,encryptedData ,iv ,}
// userInfo参数是用户无关隐私的信息
// encryptedData解密后是用于openId等隐私信息
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称
wx.getUserInfo({
success: function(res) {
console(res.userInfo)
}
})
}
}
})
},
bindGetUserInfo: function(e) {
console.log(e.detail.userInfo)
}
})
②getPhoneNumber(OBJECT):获取微信用户绑定的手机号,需先调用login接口。因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用 组件的点击来触发。
注意:目前该接口针对【非个人开发者】,且完成了认证的小程序开放。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。
Page({
getPhoneNumber: function(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
}
})
openID:用户唯一标识。28位。不需要用户同意就能获取到。
session_key: 会话密钥session_key 是对用户数据进行加密签名的密钥。为了应用自身的数据安全,只在开发服务器和微信服务器中交互,不会发送到前端。
unionID:用户在开放平台的唯一标识符。如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。29位。需要用户授权或者已经关注过公众号,具体参考UnionID。
整体流程如下图:
由于APP中有些页面默认需要登录的,如[个人中心]页面,需要登录获取到用户信息,才能继续操作。这样的页面就需要在每次进入页面(onShow
)时判断是否授权了。
profile页面:
onShow () {
login(() => {
do something...
})
}
关于登录授权相关的逻辑都可以封装在handleLogin.js
中
handleLogin.js:
// 开始login
function login (callback) {
wx.showLoading()
wx.login({
success (res) {
if (res.code) {
// 登录成功,获取用户信息
getUserInfo(res.code, callback)
} else {
// 否则弹窗显示,showToast需要封装
showToast()
}
},
fail () {
showToast()
}
})
}
// 获取用户信息
function getUserInfo (code, callback) {
wx.getUserInfo({
// 获取成功,全局存储用户信息,开发者服务器登录
success (res) {
// 全局存储用户信息
store.commit('storeUpdateWxUser', res.userInfo)
postLogin(code, res.iv, res.encryptedData, callback)
},
// 获取失败,弹窗提示一键登录
fail () {
wx.hideLoading()
// 获取用户信息失败,清楚全局存储的登录状态,弹窗提示一键登录
// 使用token管理登录态的,清楚存储全局的token
// 使用cookie管理登录态的,可以清楚全局登录状态管理的变量
store.commit('storeUpdateToken', '')
// 获取不到用户信息,说明用户没有授权或者取消授权。弹窗提示一键登录,后续会讲
showLoginModal()
}
})
}
// 开发者服务端登录
function postLogin (code, iv, encryptedData, callback) {
let params = {
code: code,
iv: iv,
encryptedData: encryptedData
}
request(apiUrl.postLogin, params, 'post').then((res) => {
if (res.code == 1) {
wx.hideLoading()
// 登录成功,
// 使用token管理登录态的,存储全局token,用于当做登录态判断,
// 使用cookie管理登录态的,可以存任意变量当做已登录状态
store.commit('storeUpdateToken', res.data.token)
callback && callback()
} else {
showToast()
}
}).catch((err) => {
showToast()
})
}
// 显示toast弹窗
function showToast (content = '登录失败,请稍后再试') {
wx.showToast({
title: content,
icon: 'none'
})
}
到此为止,登录就算完成了。不管使用token还是cookie都可以,都能有正常的登录态了,可以执行后续操作。
整个流程是 wx.login
=> wx.getUserInfo
=> 开发者服务器登录postLogin
。
某些页面默认不需要登录,但某些用户操作事件是需要登录状态的,所以一者可以判断全局存储的登录状态管理的变量,如果为false
,那么直接可以弹窗提示需要一键登录。二者如果全局状态为true
,则调用接口看接口返回的code
是否是未登录状态(此情况一般来说是登录态过期),未登录的话也弹窗提示需要一键登录。
某页面(需登录的用户操作)
getPlayer () {
// 判断全局是否有登录状态,如果没有直接弹窗提示一键登录
isLogin(() => {
let params = {
token: this.token
}
request(apiUrl.getPlayer, params).then((res) => {
// TODO: 删除打印
if (res.code === 1) {
store.commit('storeUpdateUser', res.data.player_info)
} else {
// 获取失败了,如果是code是未登录,则去登录,然后执行回调函数this.getPlayer
// 如果code不是未登录,直接弹窗报错误信息
handleError(res, this.getPlayer)
}
}).catch((err) => {
handleError(err)
})
})
}
handleLogin.js
// 判断是否登录
function isLogin (callback) {
let token = store.state.token
if (token) {
// 如果有全局存储的登录态,暂时认为他是登录状态
callback && callback()
} else {
// 如果没有登录态,弹窗提示一键登录
showLoginModal()
}
}
// 接口调用失败处理,
function handleError (res, callback) {
// 规定-3041和-3042分别代表未登录和登录态失效
if (res.code == -3041 || res.code == -3042) {
// 弹窗提示一键登录
showLoginModal()
} else if (res.msg) {
// 弹窗显示错误信息
showToast(res.msg)
}
}
到此为止,需要登录的用户操作就可以处理了。如果全局登录状态变量为true
,先去调用接口,根据返回的信息是否是未登录再处理。
由于微信小程序授权的接口wx.getUserInfo
和wx.authorize
中scope 为 "scope.userInfo" ,新版中调用这两个API是不会主动触发弹出授权窗口的。需要使用如下方式:
上面代码中多处出现的showLoginModal
是用于显示一键登录的。如下:
handleLogin.js
// 显示一键登录的弹窗
function showLoginModal () {
wx.showModal({
title: '提示',
content: '你还未登录,登录后可获得完整体验 ',
confirmText: '一键登录',
success (res) {
// 点击一键登录,去授权页面
if (res.confirm) {
wx.navigateTo({
url: '授权登录页面地址',
})
}
}
})
}
关于授权登录,我们做了一个专门的页面处理,此处的button
为:
。
如下图:
getUserInfo (e) {
if (e.target.userInfo) {
// 点击Button弹窗授权,如果授权了,执行login
// 因为Login流程中有wx.getUserInfo,此时就可以获取到了
login(() => {
// 登录成功后,返回
wx.navigateBack()
})
}
}
到此为止,整个授权和登录流程就算走完了。可以再回过头梳理一下最开始的流程图,应该就能理清整个逻辑了。
其他具体用法请参考微信小程序官方文档。