小程序登陸態控制探索全過程

前段時間折騰過一下小程序,對登陸態控制進行了一些嘗試和總結,此文以前在公衆號進行過度享,回頭看看,對目前也有必定的指導意義,因此在掘金舊文重發,但願對掘友們有所幫助前端

1、微信建議的登陸態控制

圖片來自微信
圖片來自微信

說明:
1)小程序內經過wx.login接口得到code
2)將code傳入後臺,後臺對微信服務器發起一個https請求換取openid、session_key
3)後臺生成一個自身的3rd_session(以此爲key值保持openid和session_key),返回給前端。PS:微信方的openid和session_key並無發回給前端小程序
4)小程序拿到3rd_session以後保持在本地
5)小程序請求登陸區內接口,經過wx.checkSession檢查登陸態,若是失效從新走上述登陸流程,不然待上3rd_session到後臺進行登陸驗證 redis

2、可不能夠不接受它的建議

不是我反骨,而是個人微信小程序不須要獲取什麼私密數據,用不到session_key,只須要一個openid,微信特別強調了,爲了自身應用安全,session_key 不該該在網絡上傳輸,可沒說不能夠傳輸openid,那麼若是我將openid直接返回給前端小程序,會不會方便不少?下面咱們來具體分析下:數據庫

永不過時的openid:
要知道,session_key有過時時間,必須適時從新獲取,而針對每個小程序,惟一標識用戶的openid可不會過時,若是隻在用戶第一次登陸的時候,經過後臺請求到openid,小程序緩存到本地,以後每次請求都以這個openid做爲惟一憑證,豈不是一本萬利~~小程序

事實上,上面的作法忽略了一個致命的問題,手機上是能夠切換微信帳戶的,若是手機I上原先登陸了帳戶A,已經保存了用戶A的openid,有一天手機I上切換到了帳戶B上,小程序檢測到openid存在,並不會從新獲取openid,那麼帳戶B就請求到了帳戶A的數據,這就形成數據亂象了後端

登陸態過時後從新獲取openid:
上述的問題並不能打消我使用openid做爲登陸憑證的念頭,只須要稍做改進,數據就不會亂竄:每次進入小程序經過wx.checkSession檢測登陸是否失效,若是失效從新獲取openid,要知道,手機切換了登陸帳號,登陸態必定會過時,這樣雖不能一本萬利,但也足夠省心。微信小程序

這個時候應該有一個然而,以永不過時的openid做爲登陸憑證,並非明智之舉,一旦被人截獲,就再也沒有翻身的機會了,而維護一個第三發的session,至少擁有有效期,這在很大程度上增長了安全性。而且,如今不須要使用session_key,不表明之後,保持系統的可擴展性,才能以不變應萬變緩存

事實證實,我仍是應該接受它的建議安全

3、基於redis維護3rd_session

維護3rd_session須要一個內存數據庫,這裏我選用了redisbash

維護會話態是內存數據庫的典型應用場景,畢竟量小,而且要求速度快,這麼一個小應用,固然也能夠本身在內存中維護一個對象來進行會話id的處理,可是確定難以跟一個成熟的系統相媲美服務器

拋開代碼實現,這彷佛就是一句話能夠歸納的事情,生成一個惟一的隨機串sessionid,以此爲key,openid和微信方的session_key爲value存入redis,並把sessionid傳回給客戶端。

可是,翻遍小程序的官方文檔,除了一句聽說的wx.checkSession對開發者來講是透明的,並無小程序登陸態什麼時候過時的具體說明,如何才能同步先後端的會話過時時間呢?

4、先後端會話過時時間同步

一開始,我仍是試圖尋找小程序的登陸態時效

{"session_key":"...","expires_in":7200,"openid":"..."}複製代碼

在code2session接口返回的數據中,有一個可疑的字段expires_in,它的值是7200,彷佛存儲到redis中的sessionid設置爲7200就能夠同步了。但是實踐的結果再次讓人失望,不論是設置成7200仍是60*60*24(一天),都出現了小程序會話尚在有效期,而服務器端會話已通過期的狀況,這直接致使了小程序帶着已經緩存的sessionid到服務器端請求接口,返回未登陸的狀況

看來仍是隻有wx.checkSession才知道小程序會話啥時候過時,因而,做戰方案從新作了調整,若是wx.checkSession檢測到會話失效,那麼帶上已經緩存在本地的sessionid(若是有的話),從新發起登陸請求,後臺從code2session中拿到新的請求結果後,生成新的隨機sessionid併入庫reids,而且把老的sessionid移除(若是有的話)

固然不移除也不會帶來什麼功能上的影響,可是會存在兩個問題,首先,跟使用open_id做爲登陸憑證同樣,舊的sessionid永不過時,其次,無用的session數據佔用redis資源,會拖垮訪問性能

5、「脫貧致富指數」統計

我給小程序的用戶數安了一個高大上的名字「脫貧致富指數」,純屬娛樂,切勿當真

爲了統計使用小程序的用戶數,須要一個表來保存用戶數據,後臺提供一個接口,讓小程序將用戶數據傳上來進行一個註冊操做,固然能夠把這個功能合併到登陸接口上,每次登陸都把前端小程序得到的微信用戶數據帶上,若是發現數據庫中尚未該用戶的信息,則進行入庫操做

不難發現,其實只須要用戶第一次登陸的時候註冊一次就好了,因此上述方法雖然簡便,可是有點浪費帶寬,因此應該額外提供一個註冊接口,登陸接口只須要返回一個用戶是否已經註冊的標誌,讓客戶端決定是否須要獲取用戶信息,進行註冊操做(固然後臺也不會讓同一個用戶重複入庫)

那麼問題就變成如何判斷用戶是第一次登陸了:
1)判斷登陸請求中有沒有帶上sessionid,若是沒帶上,確定是第一次登陸;若是帶上了就是登陸過的用戶?不,別忘了,前面說過,用戶可能會在同一設備切換帳戶,那就有可能在登陸接口中帶上了別人sessionid,那並不能代表用戶曾經登陸過
2)經過帶上來的sessionid從redis中拿到openid,跟在code2session新請求到的openid進行比對,若是一致,能夠證實用戶曾經登陸過,不然,仍須要用戶進行註冊

總結

時間是浪費了那麼一些,可是進過思考摸索,代碼確定更完備了~~

相關文章
相關標籤/搜索