[圖片上傳失敗...(image-11f1ea-1546674406929)]
首先要明白一件事,小程序中的登錄和授權(quán)其實(shí)是兩個(gè)操作。
登錄的意義就是讓web服務(wù)器知道當(dāng)前的用戶是誰(shuí),傳統(tǒng)的web應(yīng)用中用戶通過(guò)輸入賬號(hào)和密碼實(shí)現(xiàn)登錄,而小程序中對(duì)應(yīng)的是openId(當(dāng)前用戶對(duì)應(yīng)的唯一標(biāo)識(shí))。
每個(gè)用戶相對(duì)于每個(gè)微信應(yīng)用(公眾號(hào)或者小程序)的openId 是唯一的,也就是說(shuō)一個(gè)用戶相對(duì)于不同的微信應(yīng)用會(huì)存在不同的openId.
小程序中的授權(quán)分為很多種,使用攝像頭、錄音功能、用戶信息等等,大多數(shù)情況下通過(guò)官方提供給的wx.authorize()就可以獲取對(duì)應(yīng)的授權(quán)(彈出微信授權(quán)的對(duì)話框,用戶允許之后即可獲得),但今天要說(shuō)的用戶信息授權(quán),在小程序一系列改版之后,則需要通過(guò)其他方式獲得。
下面是前端代碼實(shí)現(xiàn)思路。
- 調(diào)用
wx.login()方法獲取code(登錄憑證),然后發(fā)送給后臺(tái),后臺(tái)就可以通過(guò)code2Session向微信服務(wù)器請(qǐng)求到openid和session_key。
mounted (){
wx.login({
success (res) {
if (res.code){
// 這里可以把code傳給后臺(tái),后臺(tái)用此獲取openid及session_key
}
},
})
}
- 只獲取到用戶的openid意義并不大,我們還需要用戶的昵稱、頭像等個(gè)人基本信息,獲取這些是需要用戶授權(quán)的。大多數(shù)情況下我們通過(guò)調(diào)用
wx.authorize()就可以向用戶發(fā)起某種授權(quán)請(qǐng)求,也就是彈窗詢問用戶是否同意授權(quán)小程序使用某項(xiàng)功能或獲取用戶的某些數(shù)據(jù)。
例如想調(diào)用設(shè)備的錄音功能:
wx.authorize({
// 通過(guò)scope指明申請(qǐng)獲取哪種類型的權(quán)限
scope: 'scope.record',
success() {
// 用戶已經(jīng)同意小程序使用錄音功能,后續(xù)調(diào)用 wx.startRecord 接口不會(huì)彈窗詢問
wx.startRecord()
}
})
會(huì)彈出以下彈窗

但是獲取用戶信息比較特殊,就像官方文檔中說(shuō)的:"wx.authorize({scope: "scope.userInfo"}),不會(huì)彈出授權(quán)窗口,請(qǐng)使用 <button open-type="getUserInfo"/>",也就是需要用戶手動(dòng)點(diǎn)擊open-type=getUserInfo的<button>組件才可以彈出請(qǐng)求權(quán)限的彈窗。
// template代碼
<button open-type="getUserInfo" @getuserinfo="bindGetUserInfo" @click="getUserInfoClick">獲取權(quán)限</button>
//script代碼
getUserInfoClick(){
// console.log('click事件首先觸發(fā)')
},
bindGetUserInfo(e) {
// console.log('回調(diào)事件后觸發(fā)')
const self = this;
if (e.mp.detail.userInfo){
console.log('用戶按了允許授權(quán)按鈕')
let { encryptedData,userInfo,iv } = e.mp.detail;
self.$http.post(api,{
// 這里的code就是通過(guò)wx.login()獲取的
code:self.code,
encryptedData,
iv,
}).then(res => {
console.log(`后臺(tái)交互拿回?cái)?shù)據(jù):`,res);
// 獲取到后臺(tái)重寫的session數(shù)據(jù),可以通過(guò)vuex做本地保存
}).catch(err => {
console.log(`api請(qǐng)求出錯(cuò):`,err);
})
} else {
//用戶按了拒絕按鈕
console.log('用戶按了拒絕按鈕');
}
},
到這里就已經(jīng)獲取到用戶的基本信息了,可以再稍微優(yōu)化一下。雖然通過(guò)wx.getUserInfo()方法已經(jīng)不能彈出授權(quán)窗口,但授權(quán)狀態(tài)會(huì)保存在緩存中,只要授權(quán)過(guò)且沒過(guò)期,便可以通過(guò)此api的success回調(diào)直接獲取到用戶信息,否則進(jìn)入會(huì)進(jìn)入fail回調(diào),此時(shí)我們?cè)偬崾居脩酎c(diǎn)擊<button>組件進(jìn)行主動(dòng)過(guò)授權(quán)即可。
// template代碼
<button v-i="buttonVisible" open-type="getUserInfo" @getuserinfo="bindGetUserInfo" @click="getUserInfoClick">獲取權(quán)限</button>
// javascript代碼
mounted () {
const self = this;
wx.login({
success (res) {
if (res.code){
self.code = res.code;
self.wxGetUserInfo(res.code);
}
},
})
},
methods: {
wxGetUserInfo (code) {
const self = this;
wx.getUserInfo({
withCredentials: true,
success (res) {
let { encryptedData,userInfo,iv } = res;
self.$http.post('api',{
code,
encryptedData,
iv,
}).then(res => {
console.log(`后臺(tái)交互拿回?cái)?shù)據(jù):`,res);
// 獲取到后臺(tái)重寫的session數(shù)據(jù),可以通過(guò)vuex做本地保存
}).catch(err => {
console.log(`自動(dòng)請(qǐng)求api失敗 err:`,err);
})
},
fail (err) {
console.log('自動(dòng)wx.getUserInfo失敗:',err);
// 顯示主動(dòng)授權(quán)的button
self.buttonVisible = true;
}
})
},
bindGetUserInfo(e) {
// console.log('回調(diào)事件后觸發(fā)')
const self = this;
if (e.mp.detail.userInfo){
console.log('用戶按了允許授權(quán)按鈕')
let { encryptedData,userInfo,iv } = e.mp.detail;
self.$http.post(api,{
// 這里的code就是通過(guò)wx.login()獲取的
code:self.code,
encryptedData,
iv,
}).then(res => {
console.log(`后臺(tái)交互拿回?cái)?shù)據(jù):`,res);
// 獲取到后臺(tái)重寫的session數(shù)據(jù),可以通過(guò)vuex做本地保存
}).catch(err => {
console.log(`api請(qǐng)求出錯(cuò):`,err);
})
} else {
//用戶按了拒絕按鈕
console.log('用戶按了拒絕按鈕');
}
},
}
到這里,就通過(guò)mpvue簡(jiǎn)單實(shí)現(xiàn)了小程序得登錄及獲取用戶信息授權(quán),總結(jié)一下:
- 首先要通過(guò)
wx.login()獲取code,也就是登錄憑證。 - 拿到code之后,引導(dǎo)用戶觸發(fā)
open-type="userinfo"的button組件,在回調(diào)事件中拿到encryptedData以及iv,與code一起傳給后臺(tái),后臺(tái)通過(guò)這些向微信服務(wù)器請(qǐng)求到openId和session_key之后,自定義登錄態(tài)并將其與openId 和session_key 關(guān)聯(lián)起來(lái)然后寫session。 - 后臺(tái)將登錄態(tài)返回給前端,前端筒骨vuex或者
wx.setStorageSync()方式講session全局保存起來(lái)。