最近看了看公司后台用戶登錄系統的設計, 比較混亂, 主要還是因為URS和Oauth以及URS第三方這三個登錄形式各不相同導致的。
下面着重介紹一下涉及到第三方登錄中需要注意的問題
在一個新項目中, 如果是要建立自己的登錄體系的話, 那么直接創建一個Users
表,包含username
和password
兩列,這樣,就可以實現登錄了:
id | username | password | name等其他字段
----+----------+----------+----------------
A1 | bob | a1b23f2c | ...
A2 | adam | c0932f32 | ...
如果要讓用戶通過第三方登錄,比如微博登錄或QQ登錄,怎么集成進來呢?
以微博登錄為例,由於微博使用OAuth2協議登錄,所以,一個登錄用戶會包含他的微博身份的ID,一個Access Token用於代表該用戶訪問微博的API和一個過期時間。
要集成微博登錄,很多童鞋立刻想到把Users
表擴展幾列,記錄下微博的信息:
id | username | password | weibo_id | weibo_access_token | weibo_expires | name等其他字段
----+----------+----------+----------+--------------------+---------------+----------------
A1 | bob | a1b23f2c | W-012345 | xxxxxxxxxx | 604800 | ...
A2 | adam | c0932f32 | W-234567 | xxxxxxxxxx | 604800 | ...
加一個QQ登錄Users
表就又需要加3列,非常不靈活
那么我們需要對這個表進行拆分。當用戶以任意一種方式登錄成功后,我們讀取到的總是Users表對應的一行記錄,它實際上是用戶的個人資料(Profile),而登錄過程只是為了認證用戶(Authenticate),無論是本地用密碼驗證,還是委托第三方登錄,這個過程本質上都是認證。
所以,如果把Profile和Authenticate分開,就十分容易理解了。Users表本身只存儲用戶的Profile, 其中ID為關聯不同登錄方式的外鍵。
id | name | birth等其他字段
----+------+-----------------
A1 | Bob | ...
A2 | Adam | ...
而通過用戶名口令登錄可視為一種Authenticate的方式,利用LocalAuth表維護:
id | user_id | username | password
----+---------+----------+-----------
01 | A1 | bob | a1b23f2c
02 | A2 | adam | c0932f32
通過微博登錄可視為另一種Authenticate方式,利用OAuth表維護, 但是access_token一般情況也只有幾個小時的時效, 所以存儲它是沒有意義的, 每次登錄的時候去微博后台驗證一下客戶端傳來的token就行了。 如果用戶只用了第三方登錄, 那就拿第三方數據來填充剛才的User表即可。
id | user_id | weibo_id |
----+---------+----------+
11 | A1 | W-012345 |
12 | A2 | W-234567 |
如果要添加另一種OAuth登錄,比如QQ登錄,那就再加一個列標示不同站點也就OK了, 但是要注意用戶在不同登錄方式的用戶名和photo一般不一樣, 所以也單獨存起來
id | user_id | oauth_name | oauth_id | nick_name| photo|
----+---------+------------+----------+----------+------+
11 | A1 | weibo | W-012345 |
12 | A2 | weibo | W-234567 |
13 | A1 | qq | Q-090807 |
14 | A2 | qq | Q-807060 |
通過這種方式, 無論用戶采用哪種方式登錄, 都可以鎖定到用戶的user_id。
下面再說一下網易的URS登錄, 因為我們要直接采用網易通行證, 所以也就不需自己存儲密碼, 因此我們的架構應該設為User表
id | user_Email | username | birth
----+------------+----------+-----------
01 | aa@126.com | bob |
02 | bb@126.com | adam |
如果用戶只用第三方登錄, 顯然無法填充user_Email這個字段, 因此userEmail可以為空。 如果第三方登錄采用的是URS第三方的接口, 它返回的oauth_id 是aa@wx.163.com這種形式。 具體設計和上面也類似。 整體上使用這種方式比現在后台的邏輯要清晰很多