微信小程序之登錄態的探索

上一篇:開發微信小程序必須要知道的事

登錄,幾乎什麼項目都會用到,其重要性不言而喻,而小程序的登錄卻一直是爲人頭疼的一件事,這裏我分享下我們在小程序登錄上的探索

通常的登錄都是通過一個表單,這很正常,但如果在小程序裏你也這麼做那就有點不可思議了,微信的一鍵登錄對用戶體驗有多好你難道不知道?不用是不是腦子有坑?最主要——你要利用微信的生態必須需要用微信的登錄,以獲取相關信息來和微信交互,OK,我們進入正題

用戶在小程序、小遊戲中需要點擊組件後,纔可以觸發登錄授權彈窗、授權自己的暱稱頭像等數據

友情提示一下:wx.login並不需要點擊組件,需要的是wx.getUserInfo,但通常我們都會用到UnionID、encryptedData、iv等信息完成完整的登錄流程,本文主要聚焦的也是這種場景

所以之前直接通過調用API的方式就行不通了,那麼問題來了——這個點擊按鈕要放到哪裏?

  • 放到首頁,一進小程序就必須先登錄。這樣顯然很粗暴,而且問題並沒有解決,反而會把用戶直接拒之門外,畢竟你不是用小程序做後臺系統,什麼場景都需要授權,先授權也是必須的
  • 在需要授權的時候跳到登陸頁面。這樣就解決了上面遇到的不需要授權的時候也被強制授權,可是這樣好嗎?

    • 體驗上不好,操作被打斷,尤其整個頁面都不需要授權只有在一個地方需要授權的,例如:你正在讀一篇文章,讀罷深有感觸,想評論一番,洋洋灑灑幾十字寫完正準備點擊呢,他媽的跳轉了!跳轉了!
    • 又一個漏斗,增加用戶流失率。還TM要登錄!很多用戶心裏一定這麼想

那就直接放在需要登錄的頁面上(這不是漏斗嗎?很多讀者一定這麼想。但想想看上面那個場景,點評論時只是需要點擊下彈出的登錄按鈕,而且還假模假樣的以微信的口吻提醒你需要登錄,那你會不會登錄?最起碼你很願意登錄,而且來的很突然,我控幾不住自己的手就點了!點了!)

可是這種方式有一個問題

怎麼在需要的頁面都能彈出登錄按鈕

應該很多人都能想到:抽離出組件,那怎麼保證在需要的頁面都有這個組件呢?錯殺一千也不能放過一個!把登錄組件集成到共用的父組件,然後在每個頁面都使用。我也建議這麼做,因爲這個共用的父組件其實又很多用處,例如iPhoneX適配等

等等,什麼都準備好了,什麼時候需要登錄呢?XX,這個肯定是你自己控制的啦。嗯~好吧,我們來理一理

在哪裏校驗是否需要鑑權

請求接口的時候,嗯~這是大家的共識

BOSS來了

怎麼鑑權

Image text

官方的這張圖已經做了很詳盡的說明,這裏不做贅述
但是看到session_key了嗎?看到官方同時說的了嗎

clipboard.png

所以問題又來了

怎麼保證session_key的有效性

誠如上圖

  • 要保證調用接口時後端session_key不失效,只能在每次調用前先使用wx.checkSession檢查是否有效
  • 實踐中也發現wx.checkSeesion非常耗時,大約200ms,所以也不能每次接口調用前都使用wx.checkSession檢查是否有效
  • 同時要注意⚠️前端不能隨便重新執行wx.login,因爲可能導致正在進行的其它後端任務session_key失效

天啦嚕,怎麼辦?!
通過實踐和偶然的發現——官方的示例代碼

clipboard.png

得知:在使用小程序期間session_key是不會失效的,so,你想到了什麼?

  • 在每個請求前去校驗有效性
  • 將校驗有效性的結果存儲起來
  • 通過async/await和剛纔存儲起來的結果來保證不過多調用wx.checkSession

先問個問題:你準備用什麼方式來存儲校驗的結果?
。。。
讓思考先飛一會
。。。。。。
。。。。。。。。。
。。。。。。。。。。。。
storage嗎?當然可以,不過不夠完美,爲什麼?因爲storage是永久的存儲,而session_key的有效期卻只是在使用小程序期間,所以你需要在小程序結束後手動重置該狀態以重新校驗其有效性,那是不是在app的onUnload裏重置呢?不是!開發過小程序的應該都知道,那就是結束使用小程序的方式太多,不能保證每種方式都會觸發onUnload,例如用戶直接銷燬了微信進程😳(其實你也可以在app的onShow裏搞)那用什麼呢?直接用內存啊,藉助內存的自動管理來智能管理,所以最終代碼應該是這樣的

// doRequest.js
let wxSessionValid = null // 微信session_key的有效性
// 帶鑑權的請求封裝
async function doRequestWithCheckAuth() {
  ...
  if (typeof wxSessionValid !== 'boolean') {
    wxSessionValid = await checkWxSession() // 檢查微信session是否有效
  }
  if (!wxSessionValid) {
    await reLogin() // 重新登錄
  }
  wxSessionValid = true // 重新登陸後session_key一定有效
  ...
}

這樣是不是看起來比較完美了?嗯~

不知道有沒有同學着急問業務側的session(自定義的登錄態)怎麼沒講?嗯,那現在講吧

怎麼校驗完整的認證體系

其實很簡單,都不想把它作爲一部分來講,但既然講了就必然有我想強調的

  • 校驗微信端的session_key略有麻煩,但不應該把它拋給服務端

    • 服務端不能直接校驗session_key的有效性而是通過調用接口發現錯誤了才知道失效了,這是被動的
    • 服務端需要同時維護兩個session

而放在前端我們只需要校驗兩個session的有效性即可,任何一個失效就重新登錄,這是積極主動有效的操作,應該被提倡

貫通

OK,基本上梳理的差不多了,就差彈登錄按鈕了,這個簡單,調用剛纔封裝的組件的方法就行了嘛,bingo,可是,點完允許後呢?怎麼繼續用戶的操作呢?怎麼能讓用戶的體驗不被打斷呢?先回放下剛纔reLogin的代碼

async function reLogin() {
  // 確保有用戶信息
  await new Promise(resolve => { // ⚠️注意開頭有await!!!
    wx.getSetting({
      success: (res) => {
        // 如果用戶沒有授權或者沒有必要的用戶信息
        if (!res.authSetting['scope.userInfo'] || !_.isRealTrue(wx.getStorageSync('userInfoRes').userInfo)) {
          navToLogin(resolve) // 去提示用戶點擊登錄按鈕,⚠️注意:並把當前的resolve帶過去
        } else {
          resolve() // 靜默登錄
        }
      }
    })
  })
  return new Promise((resolve) => {
    wx.login({
      success: res => {
        login(res.code).then((jwt) => {
          resolve(jwt) // resolve jwt
        }) // 通過code進行登錄
      },
      fail(err) {
        wx.showToast({
          title: err.errMsg,
          icon: 'none',
          duration: 2000
        })
      }
    })
  })
}
function navToLogin(resolve) {
  /* eslint-disable no-undef */
  const pages = getCurrentPages()
  const page = pages[pages.length - 1] // 當前page
  page.openLoginModal(resolve) // 打開登錄按鈕彈框,並把當前的resolve帶過去
}

上面的代碼註釋裏有兩個⚠️注意看到沒?是的,通過回調的方式😂當用戶同意授權了就繼續餘下的邏輯,如果被拒絕了,則安利他,再拒絕就終止操作,下次需要授權也會繼續彈出授權

有不明白歡迎評論留言指出,我再做說明修改
完整源碼以後會放出的,通過wepy搭建的一個框架
下一篇會講api的封裝
謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章