輕鬆籌1.6億註冊用戶的Passport賬戶系統架構

輕鬆籌是全國1.6億人使用的全民衆籌平臺,幾乎所有核心業務都依賴於賬號系統,賬號系統的用戶體驗,安全性,穩定性直接影響着輕鬆籌所有業務的運行;
輕鬆籌的發展非常迅速,已經展開了多條產品線,單點登錄的需求愈加強烈;另外由於歷史包袱的原因,也遺留了一些問題亟待解決。
本次交流主要與大家分享一下輕鬆籌賬號系統(側重登錄授權服務)的架構設計和改造方案。

歷史背景:

由於歷史包袱的遺留問題,輕鬆籌的賬號系統(登錄授權服務)之前主要存在以下幾個方面的不足:

  1. 由於歷史包袱的遺留問題,三端登錄方式不統一
  2. 產品線增多,單點登錄的需求越來越強烈
  3. 安全性不夠
  4. 容災能力不夠

設計目標:

需要達到以下幾個方面的目標

A用戶體驗:

  1. 保證只要用戶較長時間段(比如30天)內登錄過,就不需要重新登錄
  2. 單點登錄,在一個站點登錄後,另外一個站點就不需要重複登錄(用戶幾乎無感知)
  3. 採用第三方登錄的時候,能使用每一個站點對應的公衆號

B安全性:

  1. token難以僞造,具有一定不可逆性
  2. token應該有較快的過期機制,避免被人獲取token後僞造用戶操作
  3. 被惡意竊取後,具有發現機制

C穩定性:

  1. token具有自解釋性,即自帶某些信息,在某些極端惡劣情況下(比如存儲服務掛了),依然能提供服務

實現方案

概述

賬號系統最核心的功能就是登錄授權,總體思路也很簡單:

用戶登錄成功後,服務端會生成token信息,並將其和用戶信息關聯起來,返回給前端token信息,

前端攜帶token來訪問所有接口,後端再根據前端發過來的token信息標識這是哪個用戶的行爲

1 token信息的設計說明

這裏所說的token信息包括以下幾個字段(服務端生成後返回給前端的)

字段
意義
說明
備註
access_token 用戶的唯一標識 需要驗證登錄的每一個請求都需要攜帶,放在http請求頭Qsc-Token中 默認過期時間2小時
token_type token的類型 暫時保留 無用
expires_in

access_token的過期時間

前端發起請求的時候可以先用這個時間預先判斷一下,減少不必要的請求  
refresh_token 刷新token 當access_token過期時,用refresh_token去換取新的token信息 默認過期時間30天

 

服務端token存儲的信息(服務端記錄的信息)

字段
意義
說明
備註
platform android,ios,wx-h5,pc-h5等 用戶區別當前用戶是通過什麼形式登錄的 同一個平臺只維護一個token
session_id 登錄後的唯一標識,不重新登錄就不會變 不會隨着access_token和refresh_token的刷新而改變 可以用於存儲一些和登錄關聯的數據

auth_type

 登錄的方式  微信h5,微信公衆號,微信app,qq,微博,等等  


服務端存儲的數據(key-val存儲):

key(access_token) =(user_id,session_id,platform,auth_type)

key(refresh_token) =(user_id,session_id,platform,auth_type)

key(user_id,platform) =(access_token,refresh_token,expires_in,token_type)

 

說明:

  1. access_token=hex(hash(uid+time)+aes(uid+time))得到,達到目標B1
  2. access_token過期時間較短,refresh_token較長,兩者結合,達到目標A1B2
  3. token中自帶uid信息,即使服務存儲掛了,依然不影響其它業務,達到目標C1
  4. 前端h5("wxh5" "pch5" "waph5")每一個平臺僅維護一個token,多次登錄會剔除舊的,實現目標B3
  5. passport前端拿到這個token信息之後,應該記錄一下獲取時間cur_time;通過 cur_time+expires_in與當前時間 提前進行比較來判斷token是否已經過期,減少不必要的後端請求
  6. 需要登錄的接口,前端需要每次都在請求頭中寫入Qsc-Token:access_token 字段

 

當access_token過期時,用refresh_token去換取新的token信息,刷新token接口流程爲:

  1. 用戶使用refresh_token調用刷新token接口,後端判斷,若key(refresh_token)不存在,直接報錯,
  2. 若是存在,再用key(user_id,platform) 存儲的信息校驗兩者當前的refresh_token是否一致,若是不一致,說明有人利用這個token在你之前調用了刷新token接口
  3. 若是一致,則重新生成token信息,替換 key(user_id,platform) 存儲的信息,並且處理舊的信息:舊的key(access_token)直接刪掉,舊的key(refresh_token)保留一段時間

注意:

  1. 前端刷新token的時候,應該保證操作是互斥(串行)的,否則影響第上述的“踢人”功能,(app的前端互斥很好做,加鎖就可以了;h5怎麼實現前端互斥,後面會介紹)
  2. 後端刷新token的時候,應該保證操作是互斥(串行)的(分佈式鎖),保證始終只有一個token有效

 

關於踢人邏輯的說明:

需要在以下兩種情況都能達到踢人的效果:

  1. 用戶的賬號被竊取(第三方賬號,或者手機驗證碼)
  2. 用戶前端的refresh_token被竊取

解決方法:

  1. 以上兩種情況用戶操作後,都會重新生成token信息,並且替換key(user_id,platform) 存儲的信息,然後將舊的key(access_token)直接刪掉,舊的key(refresh_token)保留一段時間,這個時候這個惡意用戶是可以僞裝的
  2. 但是當原來的用戶調用刷新token接口的時候(使用的是舊的refresh_token),這個時候還是能獲得key(refresh_token)裏面的信息,再取出key(user_id,platform) 存儲的信息來校驗,會發現兩處的refresh_token是不一致的,既可以發現是被人踢下去的


特別說明:

爲什麼不用一個token隨着請求反覆刷新來達到 access_token和refresh_token的效果呢??

  1. 因爲這種方式前端頁面會有併發請求的情況,token的刷新是需要加鎖的,會帶來很大的開銷;
  2. 沒法保證前端 刷新token 的互斥,會導致反覆失效的情況

2 web-app平臺單點登錄方案

對於所有產品線的web平臺都實現單點登錄SSO(Single Sign On)的功能,這樣只要在一個產品線上(比如站點A)登錄了,在其它產品線上(比如站點B)就不需要再重新登陸了

實現目標A2,A3

注意:
  1. 如果passport本地有緩存,優先使用緩存
  2. 在token失效的時候,跳轉到passport的同時,應該把 舊的token 帶着,如果passport本地的token跟這個相同則刷新token,如果不相同,則直接返回這個token 即可
  3. 每一個站點跳轉的時候需要攜帶該站點的標識,passport 根據這個標識決定使用哪一個公衆號登錄(僅限第三方登錄)
  4. 各個站點不應該自己refresh token,在access_token 失效的時候跳轉的passport統一處理,這裏可以保證刷新token是互斥的
  5. passport前端拿到這個token信息之後,應該記錄一下獲取時間cur_time;然後把這個cur_time+expires_in+access_token 傳給各個站點
    各個站點 通過 cur_time+expires_in與當前時間 進行比較來判斷是否已經過期,
    如果過期,則不需要請求後端(當然這個時候請求後端也會返回token失效)
    各個站點可以根據自己的需要,提前過期,比如說提前一個小時就認爲token過期了,跳轉到passport重新獲取,這也是用戶體驗上的 考慮

3 native-app平臺登錄方案

對於所有產品線的ios,android等平臺暫時不考慮單點登錄的功能,但是以後會考慮(比如一個app喚起另外一個app獲取登錄token信息)

整體方案與web-app幾乎一致,但是有一些特殊性:

  1. 對於 ios,android,wxapp小程序,需要獨立開發sdk,然後各個站點統一使用同一套sdk
  2. 這個sdk應該包括ui的展現和後端的交互邏輯,統一開發,方便維護
  3. 各平臺保證ui風格統一

這裏不作過多描述

接下來 介紹一下 具體的登錄流程:
目前登錄授權支持兩種方式
1. 通過手機驗證碼登錄
2.通過第三方平臺登錄(新用戶需要綁定手機號,即再走一遍第一步


4 手機驗證碼登錄

這裏僅存在於passport前端和後端交互

流程圖:


1. 爲了防止刷短信的問題,增加了圖片驗證碼的校驗,但是考慮用戶體驗,僅僅只是在懷疑對方是惡意操作的時候
2. 爲了防止短信驗證碼的暴力破解,做了一些錯誤次數的校驗

 

5 第三方登錄(微信,微博,qq等)

流程圖:


圖中:
黃色區域指的是通過第三方平臺獲取第三方提供的code,中間需要週轉幾次,這裏省略
紅色區域指的是通過手機驗證碼登錄,就是 手機驗證碼登錄-流程圖

總結

輕鬆籌是全國1.6億人使用的全民衆籌平臺,我們的賬號系統爲平臺所有用戶提供着服務。

賬號系統其實還包含很多方面,目前還有很多不足的地方,輕鬆籌還在一直在用戶體驗,安全性,穩定性等方面持續改進。

以上 就是今天所有的分享,感謝大家抽出寶貴的時間一起交流

歡迎大家提出寶貴的意見。

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