1. 程式人生 > >健壯高效的小程式登入方案

健壯高效的小程式登入方案

登入是一項核心基礎功能,通過登入對使用者進行唯一標識,繼而才可以提供各種跟蹤服務,如收藏、下單、留言、訊息、釋出、個性化推薦等。小程式功能的方方面面大多會直接/間接涉及登入,因而,登入功能健壯與否高效與否是值得重點關注與保障的。

登入涉及的面比較多:觸發場景上,各種頁面各種互動路徑都可能觸發登入;互動過程上,既需要使用者提供/證明id,也需要後端記錄維護,還需要保證安全性;複用場景上,既是通用功能,需要多場景多頁面甚至多小程式複用,又是定製功能,需要各場景/頁面/小程式區分處理。要做到各種情形下都有良好的互動體驗,且健壯、高效、可複用、可擴充套件、可維護,還是相對比較複雜的。

本文將探討小程式登入過程中的一些主要需求和問題,以漸進迭代的方式提出並實現一個健壯、高效的登入方案。

順帶一提,es6語法中的async/await、Promise、decorator等特性對於複雜時序處理相當有增益,在本文中也會有所體現。

基礎流程

如上圖所示,基礎登入流程為:

  • 呼叫微信登入介面wx.login獲取微信登入態
  • 呼叫微信使用者資訊介面wx.getUserInfo獲取微信使用者資訊
  • 呼叫後端登入介面,根據微信使用者標識及資訊,記錄維護自己的使用者體系

該流程主要基於以下考慮:

  • 互動上,使用者只需在微信的授權彈窗上點選確認,不需要輸入賬號密碼等複雜操作;
  • 體驗上,可以直接獲取微信暱稱頭像等作為初始使用者資訊,使用起來更親切,傳播時好友辨識度也更高;
  • 開發上,可以直接使用或對映微信使用者標識,無需自己進行標識的生成和驗證;
  • 安全上,微信已經在使用者資訊的獲取、傳輸、解密等環節做了許多處理,安全性相對有保障。

健壯流程

拒絕授權問題

問題:

獲取微信使用者資訊時,會出現一個授權彈窗,需要使用者點選“允許”才能正常獲取; 若使用者點選“拒絕”,不僅當次登入會失敗,一定時間內後續登入也會失敗,因為短期內再次呼叫微信使用者資訊介面時,微信不會再向使用者展示授權彈窗,而是直接按失敗返回。 這樣導致使用者只要拒絕過一次,即使後來對小程式感興趣了願意授權了,也難以再次操作。

方案:

如上圖所示,增加以下流程以處理拒絕授權問題:

  • 獲取微信使用者資訊失敗時,判斷是否近期內拒絕授權導致;
  • 若為拒絕授權導致,則提示並開啟許可權面板,供使用者再次操作;
  • 若使用者依然未授權,則本次登入失敗,否則繼續後續流程。

這樣,使用者拒絕授權只會影響本次登入,不至於無法進行下次嘗試。

登入態過期問題

問題:

  • 微信登入態有效期不可控 上圖截自微信官方文件,從中可以看出:
    • 後端session_key隨時可能失效,什麼時候失效開發者不可控;
    • 要保證呼叫介面時後端session_key不失效,只能在每次呼叫前先使用wx.checkSession檢查有效期或直接重新執行微信登入介面;
    • 前端不能隨便重新執行微信登入介面,可能導致正在進行的其它後端任務session_key失效;此外,實踐中發現,wx.checkSession平均耗時約需200ms,每次介面呼叫前都先檢查一遍,開銷還是蠻大的。如何既保證介面功能正確有效,又不用每次耗費高額的查詢開銷,成為了一個問題。
  • 後端登入態過期 後端自身的登入態有效期也存在類似的問題,有可能在呼叫介面時才發現後端登入態已過期。

方案:

如上圖所示,增加以下流程以處理登入態過期問題:

  • 呼叫資料介面時顯式指明是否需要登入態,若需要則在介面呼叫前後自動加入登入態校驗邏輯;
  • 介面呼叫前只校驗前端登入態,不校驗後端登入態,也不校驗微信登入態,以節省每次校驗開銷;
  • 介面呼叫後校驗後端及微信登入態,若後端返回登入態相關錯誤碼,則重置前端登入態、重新登入、重新呼叫資料介面。

這樣,只有在真正需要重新登入的時候(無前端登入態/後端登入態失效/後端被提示微信登入態失效)才會重新執行登入流程;並且,一旦需要重新登入,就會自動重新觸發登入流程。

併發問題

問題:

如上圖所示,頁面各元件各功能有可能同時觸發登入流程,可能會導致:

  • 額外效能開銷,登入流程重複進行,登入介面重複呼叫;
  • 體驗問題,連續多次彈窗,影響使用者互動;
  • 邏輯問題,後一次登入重新整理了前一次登入的session_key,導致前一次登入介面解碼失敗,返回異常結果。

方案:

如上圖所示,加入免併發邏輯:若登入流程正在進行,則不重複觸發登入流程,而是加入當前流程的監聽佇列,待登入結束時再一併處理。這樣,任一時刻最多隻有一個登入流程正在進行。

流程實現

時序控制

如上圖所示,目前登入流程已較為複雜,步驟較多,且大多是非同步操作,每步成功失敗需要區分處理,處理過程又會相互交織。如果直接在微信介面/網路介面提供的success/fail回撥中進行邏輯處理,會造成:

  • 回撥層層巢狀,影響程式碼書寫和閱讀;
  • 不同路徑公共步驟難以統一提取;
  • 時序邏輯不直觀,不易管理。

因而採用Promise+async/await進行時序管理:

  • 將每個步驟Promise化: JavaScript
    123456789101112131415161718192021222324252627282930 classLogin{static_loginSteps={//各登入步驟/**     * 微信登入:呼叫微信相關API,獲取使用者標識(openid,某些情況下也能獲得unionid)     * <a href='http://www.jobbole.com/members/wx1409399284'>@return</a> {Promise<Object>} 微信使用者標識     */wxLogin(){returnnewPromise((resolve,reject)=>{//結果以Promise形式返回wx.login({success(res){resolve(Object.assign(res,{succeeded:true}));//成功失敗都resolve,並通過succeeded欄位區分},fail(res){resolve(Object.assign(res,{succeeded:false}));//成功失敗都resolve,並通過succeeded欄位區分},})});},/**     * 獲取微信使用者資訊:呼叫微信相關API,請求使用者授權訪問個人資訊     * <a href='http://www.jobbole.com/members/wx1409399284'>@return</a> {Promise<Object>} 微信使用者資訊     */requestUserInfo(){returnnewPromise((resolve,reject)=>{//結果以Promise形式返回//... });},//...}}
  • 使用async/await管理整體時序: JavaScript
    123456789101112131415161718192021222324252627282930 classLogin{staticasync _login(){//管理整體時序//....let steps=Login._loginSteps;//微信登入let wxLoginRes=await steps.wxLogin();if(!wxLoginRes.succeeded)//微信登入介面異常,登入失敗return{code:-1};//獲取微信使用者資訊let userInfoRes=await steps.requestUserInfo();if(!userInfoRes.succeeded&&userInfoRes.failType==='userDeny'){//使用者近期內曾經拒絕授權導致獲取資訊失敗await steps.tipAuth();//提示授權let settingRes=await steps.openSetting();//開啟許可權面板if(!settingRes.succeeded)//使用者依然拒絕授權,登入失敗return{code:-2};userInfoRes=await steps.requestUserInfo();//使用者同意授權,重新獲取使用者資訊}if(!userInfoRes.succeeded)//其它原因導致的獲取使用者資訊失敗return{code:-3};//獲取使用者資訊成功,進行後續流程//....}}

如以上程式碼所示,微信登入、獲取微信使用者資訊、提示授權、開啟許可權面板等每一步都是非同步操作,都要等待success/fail回撥才能獲得操作結果併發起下一個操作;但利用Promise+async/await,可以像普通流程一樣,將這些操作線性組合,順序處理。 這樣,就可以實現直觀清晰的時序管理了。

過期處理

JavaScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 classLogin{/**    *登入    */staticasync login(options){if(Login.checkLogin())//若已有前端登入態,則直接按登入成功返回return{code:0};//否則執行登入流程//...}/**    * 普通資料請求,不進行登入態檢查,結果以Promise形式返回    * @param {Object}options 引數,格式同wx.request    * <a href='http://www.jobbole.com/members/wx1409399284'>@return</a> {Promise} 請求結果,resolve時為資料介面返回內容, reject時為請求詳情    */staticasync request(options){returnnewPromise((resolve,reject)=>{wx.request(Object.assign({},options,{success(res){resolve(res.data);},fail(res){reject(res);}});});}/**     * 要求登入態的資料請求,封裝了登入態邏輯     * @param {Object} options 請求引數,格式同wx.request     * @param {Object} options.loginOpts 登入選項,格式同login函式     * <a href='http://www.jobbole.com/members/wx1409399284'>@return</a> {Promise} 返回結果,resolve時為資料介面返回內容, reject時為請求詳情     */staticasync requestWithLogin(options){//先校驗/獲取前端登入態,保證大部分情況下請求發出時已登入let loginRes=await Login.login(options.loginOpts);if(loginRes.code!=0)thrownewError('login failed, request not sent:'+options.url);//傳送資料請求let resp=await Login.request(options);//若後端登入態正常,則正常返回資料請求結果if(!Login._config.apiAuthFail(resp,options))//根據後端統一錯誤碼判斷登入態是否過期returnresp;//若後端登入態過期Login._clearLoginInfo();//重置前端登入態,保證後續再次呼叫login時會真正執行登入環節returnLogin.requestWithLogin(options);//重新登入,重新發送請求,並將重新發送的請求的返回結果作為本次呼叫結果予以返回}}

如以上程式碼所示,單獨封裝一個requestWithLogin函式,在資料請求前後加入登入態處理邏輯,可以保證資料請求會在有後端登入態時被髮送/重新發送。 並且,重新登入過程對資料介面呼叫方是完全透明的,呼叫方只需要知道自己的介面需不需要登入態,而無需進行任何登入態相關判斷處理,重登入過程也不會對介面呼叫返回結果造成任何影響。 這樣,就可以實現登入態過期自動重新登入了。

併發控制

JavaScript
12345678910111213141516171819202122 classLogin{static_loginSingleton=null;//正在進行的登入流程staticasync _login(){//登入流程...}//封裝了免併發邏輯的登入函式staticasync login(){if(Login._loginSingleton)//若當前有登入流程正在進行,則直接使用其結果作為本次登入結果returnLogin._loginSingleton;//否則觸發登入流程Login._loginSingleton=Login._login();//並在登入結束時釋放併發限制Login._loginSingleton.then(()=>{Login._loginSingleton=null}).catch(()=>{Login._loginSingleton=null});//返回登入結果      returnLogin._loginSingleton;}}

如以上程式碼所示,利用Promise可以被多次then/catch的特性(亦即,一個async函式呼叫結果可以被await多次),可以使用一個Promise來記錄當前登入流程,後續呼叫直接對該Promise進行監聽。 這樣,就可以實現登入流程免併發了。

至此,我們就得到了一個功能可用、相對健壯、相對高效的登入模組。但依然還是存在優化空間的。

場景優化

二次授權問題

問題: 使用者同意授權後,小程式可以訪問到微信使用者資訊,並且一段時間內再次訪問時,也不會重新出現授權彈窗; 但是,如果使用者長時間未使用小程式,或將小程式刪除重進,則登入時會再次出現授權彈窗。 一方面會對使用者造成干擾,影響其瀏覽效率;另一方面,不利於流失使用者召回。

方案: 再次授權場景其實並不是很必要:

  • 使用者第一次授權時,開發者已經可以獲得使用者暱稱、頭像等使用者資訊和openid、unionid等使用者標識;
  • 再次授權時,雖然使用者資訊可能有更新,但完全可以等使用者進個人主頁/編輯資訊時再進行同步,沒必要剛進小程式就彈窗;
  • 再次授權時,使用者標識並不會變化;
  • 只調用微信登入介面,不觸發授權,已經可以獲得openid了,通過openid就可以從資料庫中查詢使用其上次授權時的使用者資訊和unionid等其它使用者標識。

因而,增加以下流程以優化二次授權場景:

如上圖所示,在微信登入介面呼叫成功之後,先嚐試直接根據openid完成登入過程,若失敗再去請求使用者授權。

這樣,只有新使用者才會出現授權彈窗;老使用者、迴歸使用者,都可以直接靜默完成登入過程。

場景適配問題

問題: 不同場景對登入行為可能有不同的期望:

  • 有些場景,希望只在需要時自動登入,如商品詳情頁,希望在使用者點選留言、收藏等按鈕時自動調起登入並完成留言、收藏等相應操作;
  • 有些場景,希望只嘗試靜默登入,如首頁,希望對使用者做個性化推薦和針對性投放,但又不願彈窗阻撓使用者;
  • 有些場景,希望保證前後端登入態一致,如微信介面資料解碼。

單一的登入流程很難滿足這種多元的場景需求。

方案: 呼叫登入/要求登入的資料介面時支援指定場景模式:

如上圖所示,登入流程支援指定不同場景模式:

  • 通用模式,為預設模式,會自動調起登入並完成相應資料請求和後續操作;
  • 靜默模式,只會嘗試靜默登入,不會嘗試授權登入,成功與否均不影響頁面功能和後續介面呼叫;
  • 強制模式,會重新登入,不管前端是否保有登入態,以保證前後端登入態同步。

實現

場景優化方案主要是增加了一些流程&判斷,使用上文中的“時序控制”基本可以解決。 主要難點在於,上文中的免併發機制不再適用。比如,靜默模式正在進行時又觸發了一個強制模式的請求,此時,應觸發授權彈窗正常登入而不是監聽使用靜默模式的登入結果。 如果拆成每個模式各自免併發,一方面,登入流程需重複書寫,不便複用;另一方面,模式之間併發也存在風險。 因而,引入公共步驟併合機制:

JavaScript

相關推薦

健壯高效程式登入方案

登入是一項核心基礎功能,通過登入對使用者進行唯一標識,繼而才可以提供各種跟蹤服務,如收藏、下單、留言、訊息、釋出、個性化推薦等。小程式功能的方方面面大多會直接/間接涉及登入,因而,登入功能健壯與否高效與否是值得重點關注與保障的。 登入涉及的面比較多:觸發場景上,各種頁面各種互

微信程式登入授權

wxml檔案內容 <view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInf

微信程式登入-openid和unionid

本文轉自https://www.cnblogs.com/yaoyuqian/p/8203792.html   我們一般都是先獲取到微信的 unionid,然後再通過 unionid 去登入自己的網站,就可以關聯到使用者在自己網站上的 user_id,但是在小程式登入中,有時候可以獲取到

程式登入——PHP後臺處理資料庫的完整過程以及程式碼

    注:這裡用到的是本地測試,所以後面的URL網址並沒有使用https。       你需要做的幾件小事: 頁面 php mysql      關於頁面,直接貼程式碼。具體自

解決微信程式登入與釋出的一些問題

解決微信小程式的問題 圖片在電腦上顯示但在手機上卻無法顯示的問題 要使用的是本地圖片,不想把圖片上傳到網路再通過https的方式解決,解決方法如下: 1.image src中的圖片地址對英文字母大小寫敏感,必須確認大小寫對得上; 2.圖片大小問題。本地圖片要小於10KB才能順利在真機上顯示。 為什麼

程式登入個人見解

我小程式端儲存srd為使用者登入標識 後臺  把使用者資訊存到redis(有時效的)裡面   在需要登入的地方點選驗證........ 頁面載入onLoad(有的頁面需驗證登入是否過期)..........   點選評論 //底部發表評論

解決方案 [微信程式] megalo -- 網易考拉程式解決方案

轉自:http://www.okeydown.com/(微信小程式網) 作者: webadmin 釋出時間: 2018-10-29 13:48:36 導語: megalo 是基於 Vue 的小程式框架(沒錯,又是基於 Vue 的小程式框架),但是它不僅僅支援微信小程式,

程式登入(java後臺)

基本順序 1.微信小程式的appId 2.微信小程式的secret 3.ip在微信公眾號裡備案 4.新增業務域名會訪問專案中的MP_verify_fQ6FF0R8GZHgK5Kl.txt (程式實現這個檔案) 5.wx.login()獲取微信給的臨時code 5分鐘有

微信程式--登入流程梳理

前言 微信小程式凡是需要記錄使用者資訊都需要登入,但是也有幾種不同的登入方式,但是在小程式部分的登入流程是一樣的。之前就朦朦朧朧地用之前專案的邏輯改改直接用了,這個新專案要用就又結合官方文件重新梳理了下,並記錄一下,好記性不如爛筆頭嘛,哈哈。 幾種登入流程設計 利用OpenId 建立新使用者 這種方式

程式跳轉程式,長按識別程式碼跳轉程式解決方案

場景描述: 因為小程式跳轉的時候需要公眾號關聯,但是關聯的數量是有限的!因此該文章的處理方案是: a.關聯的小程式,直接可以點選開啟 b.沒有關聯的,那麼可以長按識別小程式碼來進入小程式 下面展示效果: 1.點選關聯有appid的時候,直接進入小程式 2.點選沒有appid的

基於Shiro,JWT實現微信程式登入完整例子

小程式官方流程圖如下,官方地址 : developers.weixin.qq.com/miniprogram… : 如果此圖理解不清楚的地方,也可參看我的部落格 : www.cnblogs.com/ealenxie/p/… 本文是對接微信小程式自定義登入的一個完整例子實現 ,技術棧為 :

php程式登入時解密getUserInfo獲取openId和unionId等敏感資訊

在獲取之前先了解一下openId和unionId openId : 使用者在當前小程式的唯一標識  unionId : 如果開發者擁有多個移動應用、網站應用、和公眾帳號(包括小程式),可通過unionid來區分使用者的唯一性,因為只要是同一個微信開放平臺帳號下的移動應用、網站應用和公眾帳號(

程式登入

<?php include_once "wxBizDataCrypt.php"; $appid = 'APPID'; $sessionKey = '金鑰'; $encryptedData=""; $iv = 'r7BXXKkLb8qrSNn05n0qiA=='; $pc = new

微信程式佈局方案(block+flex)

微信小程式 View 支援兩種佈局方式:Block 和 Flex 所有 View 預設都是 block 要使用 flex 佈局的話需要顯式的宣告(給父元素): display:flex; 下面就來介紹下微信小程式的 Flex 佈局 先做一個簡單的 demo

Java開發微信程式登入介面

先說一下需求吧,小程式微信登入,使用者授權獲取個人資訊。然後儲存使用者基本資訊到系統使用者表,同時新增使用者賬戶資訊,上傳使用者頭像。 emmm..之所以想寫下來是因為自己踩過的坑啊。。就不細說了。 連結: 小程式微信登入官方文件   登入: 之後開發者伺服

程式登入、微信網頁授權(Java版)

首先呢,“登入”、“授權”、“授權登入”,是一樣的意思,不用糾結。 寫小程式授權登入的程式碼前,需要了解清楚openid與unionid的區別,這裡再簡單介紹一下: 騰訊有個 “微信·開放平臺”,只有企業才能註冊賬號,可理解為微信體系裡,最頂級的賬號。官網地址:https://open.w

程式解決方案 Westore

## 資料流轉 先上一張圖看清 Westore 怎麼解決小程式資料難以管理和維護的問題: ![](https://img2018.cnblogs.com/blog/105416/201810/105416-20181008101849931-1044477325.jpg) 非純元件的話,可以

微信程式登入Java後臺介面(詳解,附示例程式碼)

首先看一下官方文件 我們先對官方給的時序圖進行簡單的分析 1.當小程式呼叫wx.login()時,會獲得一個code(臨時登入憑證),然後我們需要用wx.request()將code傳送到自己的伺服器. 2.在伺服器的介面中,呼叫登入憑證校檢介面,將appid(

公眾號電商程式運營方案

公眾號電商是通過優質內容連結使用者與產品,是一種以內容為媒介,以產品銷售、流量變現為目的的線上銷售模式。通過優質的內容聚合粉絲,粉絲在閱讀過程中購買商品,完成消費。 以內容為導向的公眾號電商更容易打造自身品牌IP,實現粉絲的精確觸達與精準引導。 移動網際網路網民增長觸達天花板,

電商程式運營方案

隨著消費環境的改變,傳統電商模式的痛點日益尖銳,成本高、留存難等弊端顯露,中小品牌出現生存難題, 轉型升級迫在眉睫。 在移動網際網路的下半場,流量池成為商家的必爭之地。基於微信而生的小程式背靠10億流量,自帶社交屬性,同 時以品牌為基礎的特性實現了去中心化,成為傳統電商轉型的新趨勢