這篇文章主要介紹了小程序:授權、登錄、session_key、unionID、openID等的詳解,主要分爲兩個部分來介紹,第一部分是簡單的整理說明,以求理清關係。第二部分授權登錄的邏輯參考了多個小程序,希望能找到最優的模式,並會配合代碼詳細講解整個流程。
目錄
一、API詳解
1.登錄
通過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.login()調用時,用戶的session_key會被更新而致使舊session_key失效。
- 微信不會把session_key的有效期告知開發者。
- 開發者在session_key失效時,可以通過重新執行登錄流程獲取有效的session_key。
- 當開發者在實現自定義登錄態時,可以考慮以session_key有效期作爲自身登錄態有效期,也可以實現自定義的時效性策略。
wx.checkSession({
success: function(){
//session_key 未過期,並且在本生命週期一直有效
},
fail: function(){
// session_key 已經失效,需要重新執行登錄流程
wx.login() //重新登錄
}
})
也就是說,每次打開應用時,檢測微信session_key是否過期,如果沒過期什麼都不用做,如果過期了重新登錄獲取微信session_key。然後獲取開發服務器的session,從而達成正真意義上的登錄。
2.授權
當小程序需要用戶操作(比如:關注、評論、添加購物車、地理位置、個人中心等等),就需要用戶先授權。
①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()
}
})
}
}
})
3.用戶信息
①wx.getUserInfo(OBJECT)
注意:此接口有調整,使用該接口將不再出現授權彈窗,請使用下面代碼來引導用戶主動進行授權操作。
<button open-type="getUserInfo"></button>
- 當用戶未授權過,調用該接口將直接報錯
- 當用戶授權過,可以使用該接口獲取用戶信息
<!--wxml-->
<!-- 如果只是展示用戶頭像暱稱,可以使用 <open-data /> 組件 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
<!-- 需要使用 button 來授權登錄 -->
<button wx:if="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授權登錄</button>
<view wx:else>請升級微信版本</view>
//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 來調用,需用 <button>
組件的點擊來觸發。
注意:目前該接口針對【非個人開發者】,且完成了認證的小程序開放。需謹慎使用,若用戶舉報較多或被發現在不必要場景下使用,微信有權永久回收該小程序的該接口權限。
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"> </button>
Page({
getPhoneNumber: function(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
}
})
4.部分字段解釋
openID:用戶唯一標識。28位。不需要用戶同意就能獲取到。
session_key: 會話密鑰session_key 是對用戶數據進行加密簽名的密鑰。爲了應用自身的數據安全,只在開發服務器和微信服務器中交互,不會發送到前端。
unionID:用戶在開放平臺的唯一標識符。如果開發者擁有多個移動應用、網站應用、和公衆帳號(包括小程序),可通過unionid來區分用戶的唯一性。換句話說,同一用戶,對同一個微信開放平臺下的不同應用,unionid是相同的。29位。需要用戶授權或者已經關注過公衆號,具體參考UnionID。
二、登錄授權流程
1.模式概覽
整體流程如下圖:
2.主動登錄
由於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
。
3.調用接口
某些頁面默認不需要登錄,但某些用戶操作事件是需要登錄狀態的,所以一者可以判斷全局存儲的登錄狀態管理的變量,如果爲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
,先去調用接口,根據返回的信息是否是未登錄再處理。
4.彈窗提示
由於微信小程序授權的接口wx.getUserInfo
和wx.authorize
中scope 爲 "scope.userInfo" ,新版中調用這兩個API是不會主動觸發彈出授權窗口的。需要使用如下方式:
<button open-type="getUserInfo"></button>
上面代碼中多處出現的showLoginModal
是用於顯示一鍵登錄的。如下:
handleLogin.js
// 顯示一鍵登錄的彈窗
function showLoginModal () {
wx.showModal({
title: '提示',
content: '你還未登錄,登錄後可獲得完整體驗 ',
confirmText: '一鍵登錄',
success (res) {
// 點擊一鍵登錄,去授權頁面
if (res.confirm) {
wx.navigateTo({
url: '授權登錄頁面地址',
})
}
}
})
}
關於授權登錄,我們做了一個專門的頁面處理,此處的button
爲:
<button type="primary" v-if="canIUse" open-type="getUserInfo" @getuserinfo="getUserInfo">微信登錄</button>。
如下圖:
getUserInfo (e) {
if (e.target.userInfo) {
// 點擊Button彈窗授權,如果授權了,執行login
// 因爲Login流程中有wx.getUserInfo,此時就可以獲取到了
login(() => {
// 登錄成功後,返回
wx.navigateBack()
})
}
}
到此爲止,整個授權和登錄流程就算走完了。可以再回過頭梳理一下最開始的流程圖,應該就能理清整個邏輯了。
其他具體用法請參考微信小程序官方文檔。