轉自 繆雪峯老師的文章,用來學習設計表
--------------------------------------------------------------
在Web系統中,用戶登錄是最基本的功能。要實現用戶名+密碼登錄,很多同學的第一想法就是直接創建一個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 | name | birth等其他字段
----+------+-----------------
A1 | Bob | ...
A2 | Adam | ...
而通過用戶名口令登錄可視爲一種Authenticate的方式,利用LocalAuth表維護:
id | user_id | username | password
----+---------+----------+-----------
01 | A1 | bob | a1b23f2c
02 | A2 | adam | c0932f32
通過微博登錄可視爲另一種Authenticate方式,利用OAuth表維護:
id | user_id | weibo_id | weibo_access_token | weibo_expires
----+---------+----------+--------------------+---------------
11 | A1 | W-012345 | xxxxxxxxxx | 604800
12 | A2 | W-234567 | xxxxxxxxxx | 604800
如果要添加另一種OAuth登錄,比如QQ登錄,增加一個表就可以了。不過既然大家都是OAuth家族的,不如統一到一個表,給每家起個名字區分就好了:
id | user_id | oauth_name | oauth_id | oauth_access_token | oauth_expires
----+---------+------------+----------+--------------------+---------------
11 | A1 | weibo | W-012345 | xxxxxxxxxx | 604800
12 | A2 | weibo | W-234567 | xxxxxxxxxx | 604800
13 | A1 | qq | Q-090807 | xxx-xxx-xxx | 86400
14 | A2 | qq | Q-807060 | xxx-xxx-xxx | 86400
如果要增加一種新的登錄方式,比如SAML,那就再加一種類型的表。
有些網站需要API訪問,API可以使用api_key和api_secret來認證,可是怎麼把一個API訪問關聯到一個用戶?方法還是增加一種API Auth的表:
id | user_id | api_key | api_secret
----+---------+----------+------------
11 | A1 | a-012345 | xxxxxxxxxx
12 | A2 | a-234567 | xxxxxxxxxx
每一種X-Auth表都存儲了用戶的登錄認證信息,並通過user_id
關聯到Users
表。這樣一來,不但登錄過程簡化了,而且一個用戶可以使用多種方式登錄。只要登錄成功,拿到了user_id
,最後讀取Users
表是爲了獲得用戶的Profile,這樣讀出來的數據也更安全,因爲Users
表不包含用戶口令,不會因爲暴露API而不小心把口令給泄露出去。