淺談數(shù)據(jù)庫用戶表結(jié)構(gòu)設(shè)計&第三方登錄

? 說起用戶表 , 大概是每個應(yīng)用/網(wǎng)站立項動工考慮的第一件事情 ; 用戶表結(jié)構(gòu)的設(shè)計 , 算是整個后臺架構(gòu)的基石 ; 如果基石不穩(wěn) , 待到后面需求跟進了發(fā)現(xiàn)不能應(yīng)付 , 回過頭來反復(fù)修改用戶表 , 要大大小小作改動的地方也不少 ; 與其如此 , 不妨設(shè)計用戶表之初就考慮可拓展性 , 爭取不需要太多額外代價的情況下一步到位 ;

先前設(shè)計

id
username
password

? 用戶名加上密碼 , 解決簡單需求 , 留個 ID 作為其他表的外鍵 ; 當然 , 那時候密碼還可能是明文存儲 , 好點的知道 MD5 ;

? 后來呢 , 隨著業(yè)務(wù)需求的拓展 , 要加個用戶狀態(tài) status 判斷用戶是否被封禁 , 注冊時間和注冊 IP 地址 , 上次登錄時間和 IP 地址備查 (并衍生出登錄記錄表 , 用來判斷是否異地登錄等 , 在此不表) , 用戶角色/權(quán)限 role (又衍生出用戶角色權(quán)限關(guān)系 , 還是另文討論) , 業(yè)務(wù)也需要個人的個人信息如真實姓名 , 地址等也一股腦往上添加 , 現(xiàn)在形成了一個很完整的用戶關(guān)系表 ;

id
username
password
realname
address
…
status
role
register_time
register_ip
login_time
login_ip

? 現(xiàn)在問題來了 , 進入 Web2.0 時代 ,微博開放了第三方網(wǎng)站登錄 , 用微博帳號就能登錄我們的網(wǎng)站 , 老板說 , 這個我們得要 , 加個微博用戶登錄表吧 , 當然 , 得和我們自己的用戶表關(guān)聯(lián) , 這個微博用戶信息表如下 :

id    自增 ID
user_id    關(guān)聯(lián)本站用戶 ID
uid    微博唯一 ID
access_token
access_expire

? 這還不算完 , QQ又開放用戶登錄了 , 一下子要接入好多家第三方登錄了 , 只能就著 “微博用戶信息表” 繼續(xù)加類型加判斷 , 如果是每個第三方登錄都新建一個表 , 肯定會瘋的 ;
時代變了 , 進入了移動互聯(lián)網(wǎng)時代 , 怎么也得支持個手機號登錄吧 , 所以現(xiàn)在每家標配都是 : 用戶名/郵箱/手機號 登錄 , 外加一系列微博 , 微信等第三方登錄 , 表結(jié)構(gòu)如下 :

用戶表

id
username
email
phone
…

用戶第三方登錄表

id
user_id
app_type
app_user_id
access_token
…

? 用戶在輸入框輸入 用戶名/郵箱/手機號和密碼 之后 , 后臺判斷是郵箱 , 手機號或是用戶名 , 再根據(jù)條件查詢是否為特定用戶 ;
? 這個表結(jié)構(gòu)能夠承載未來一段時間的業(yè)務(wù)需求了 , 如果說某天冒出了一個新的登錄方式 , 比如身份證號登錄 , 怎么辦 ? 繼續(xù)在用戶表加字段 ? 我覺得有更好的選擇 ;

改進版

? 無論 username + password , 還是 phone + password , 都是一種 用戶信息+密碼 的驗證形式特占;再來理解第三方登錄 , 其實它也是用戶信息+密碼的形式 , 用戶信息即第三方系統(tǒng)中的 ID (第三方登錄一定會給一個在他們系統(tǒng)中的唯一標識) , 密碼即 access_token , 只不過是一種有使用時效定期修改的密碼 ; 所以我們把它抽象出了用戶基礎(chǔ)信息表加上用戶授權(quán)信息表的形式 ;

用戶基礎(chǔ)信息表 users

id
nickname
avatar

用戶授權(quán)信息表 user_auths

id
user_id
identity_type    登錄類型 (手機號/郵箱/用戶名) 或第三方應(yīng)用名稱 (微信 , 微博等)
identifier    標識 (手機號/郵箱/用戶名或第三方應(yīng)用的唯一標識)
credential    密碼憑證 (站內(nèi)的保存密碼 , 站外的不保存或保存 token)

? 這個系統(tǒng)最大的特色就是 , 用戶信息表不保存任何密碼 , 不保存任何登錄信息 (如用戶名 , 手機號 , 郵箱) , 只留有昵稱 , 頭像等基礎(chǔ)信息 ; 所有和授權(quán)相關(guān) (且基本[前端]展示無關(guān)的) , 都放在用戶信息授權(quán)表 , 用戶信息表和用戶授權(quán)表是一對多的關(guān)系 ; 說起來太抽象 , 表現(xiàn)如下 :

users

|id|nickname|avatar|
|1|慕容雪村|http://…/avatar.jpg|
|2|魔力鳥|http://…/avatar2.jpg|
|3|科比|http://…/avatar3.jpg|

user_auths

|id|user_id|identity_type|identifier|credential|
|1|1|email|123@example.com|password_hash(密碼)|
|2|1|phone|13888888888|password_hash(密碼)|
|3|1|weibo|微博UID|微博access_token|
|4|2|username|moliniao|password_hash(密碼)|
|5|3|weixin|微信UserName|微信token|

說說具體處理 , 用戶發(fā)來 郵箱/用戶名/手機號和密碼 請求登錄的時候 , 依然是先判斷類型 , 以某用戶使用了手機號登錄為例 , 使用 select * from user_auths where type= 'phone' and identifier= '手機號' 查找條目 , 如有 , 取出并判斷 password_hash (密碼)是否和該條目的 credential 相符 , 相符則通過驗證 , 隨后通過 user_id 獲取用戶信息 ;
如果使用第三方登錄 , 則只要判斷 select * from user_auths where type= 'weixin' and identifier= '微信UserName' , 如果有記錄 , 則直接登錄成功 , 使用新的 token 更新原 token ; 假設(shè)與微信[服務(wù)器]通信不被劫持的情況下無需判斷憑證問題 ;

優(yōu)缺點``

通過這個表結(jié)構(gòu)設(shè)計 , 使許多原來糾結(jié)的問題瞬間解決 , 說說優(yōu)點 :

  • 站內(nèi)登錄類型無限拓展 , 代碼改動小 ; 如果真要支持身份證登錄了 , 只要少許幾處改動 , 無需修改表結(jié)構(gòu) ;
  • 第三方登錄類型可用工場模式批量拓展 , 新增第三方登錄類型的開發(fā)成本降到最低 ;
  • 原來條件下 , 應(yīng)用需要驗證手機號是否已驗證和郵箱是否已驗證 , 需要相對應(yīng)多一個字段如 phone_verified 和 email_verified , 如今只要在 user_auths 表中增加一個統(tǒng)一的 verified 字段 , 每種登錄方式都可以直觀看到是否已驗證情況 ; 基于信任第三方登錄的數(shù)據(jù)準確性 , 默認第三方登錄都是已驗證 ; 如果用戶修改登錄手機號或登錄郵箱 , 也能清晰跟蹤每一步的完成度 ;
  • 可按需綁定任意數(shù)量的同類型登錄方式 , 即一個用戶可以綁定多個微信 , 可以有多個郵箱 , 可以有多個手機號 , 是不是很贊 ? 當然你也可以限制一種登錄方式只有一條記錄 ;
  • 在 user_auths 添加相應(yīng)的時間和 IP 地址 , 就可以更加完整地跟蹤用戶的使用習(xí)慣 , 比如 , 已經(jīng)不使用微博登錄兩年多 , 已經(jīng)綁定微信 300 天
  • 即使完全使用第三方帳號登錄 , 可在前端做到 “無需注冊本站帳號” 的效果 ; 過去許多網(wǎng)站雖然支持第三方帳號登錄 , 但出于留存用戶等原因 , 第一次微博登錄回來 , 讓你再填寫一套他們網(wǎng)站的郵箱 , 密碼等信息 , 也就失去了微博登錄的最大意義 ; 從技術(shù)上說 , 原有的結(jié)構(gòu)導(dǎo)致除了在微博用戶表建立一個條目外 , 必須在用戶表建立一條對應(yīng)的條目 , 而且一般情況下不能讓用戶表里的郵箱或者用戶名和密碼留空 ; 用戶體驗好的 , 郵箱自動生成微博ID@id.weibo.sina.com , 密碼則隨機生成 ; 至于體驗不好的 , 只能說早知道還不如不用微博登錄呢 ! 現(xiàn)在呢 , 我們的這個用戶表結(jié)構(gòu)則完全沒有這樣的困擾 , 只要微博提供的昵稱和頭像地址就可以生成這個用戶 , 再關(guān)聯(lián)他的微博登錄記錄 ; 而且我們的表結(jié)構(gòu)意味著 , 用戶可以解除他的所有登錄方式 , 于是這個賬戶變徹底變成了沒法登錄的僵尸 (解決辦法是在代碼里加一個限制 , 至少保留一條user_auths的記錄) ; 如果你非得得到用戶的郵箱 , 那么每次登錄的時候看到他不存在一條 identify_type 為 email 的記錄 , 則彈窗彈死他 , 讓他趕快填郵箱 , 否則啥都別干 ;
  • 提升了邏輯思維能力 , 抽象出事物本質(zhì)是碼農(nóng)必備職業(yè)素養(yǎng) , 通過對用戶表結(jié)構(gòu)的學(xué)習(xí)研究 , 提高了鄙人的各方面技能 , 從此寫代碼一路順風(fēng)順水…
  • 如果你說郵箱和手機號就是用戶信息的組成部分 , 他們依然需要體現(xiàn)在 users 表中作為前端展示似芝?沒問題 , users 表盡管拓展 , users 表里依然有email , phone , 但他們僅僅作為 “展示用途” , 和昵稱 , 頭像 , 或者性別這些屬性沒有本質(zhì)區(qū)別 ; 在用戶信息表與用戶授權(quán)登錄拆分后 , 用戶信息表可以隨時增加任意字段 , 加星座 , 加生日 , 都沒問題 , 只需要在前端展示時多幾個輸入框 , 錄入時多幾行代碼 , 與用戶登錄相關(guān)的問題做到最大程度解耦 ;

有利必有弊 , 說說缺點 :

  • 原先的用戶判斷由 1 次 SQL 變成 2 次 SQL 請求 ;
  • 用戶同時存在郵箱 , 用戶名 , 手機號等多種站內(nèi)登錄方式時 , 改密碼時必須一起改 , 否則就變成了 郵箱 + 新密碼 , 手機號 + 舊密碼訪問了 , 肯定是很詭異的情況 ; 如果考慮到這一點 , 又要在 user_auths 表中新增一個表示站內(nèi)登錄方式或第三方登錄方式的標識字段 ;
  • 代碼量增加了 , 有些情況下邏輯判斷增加了 , 難度增大了 ; 舉個例子 , 無論用戶是否已登錄 , 無論用戶是否已注冊過 , 都是點擊同一鏈接前往微博第三方授權(quán)后返回 , 可能出現(xiàn)幾種情況 : 1 , 該微博在本站未注冊過 , 很好 , 直接給他注冊關(guān)聯(lián)并登錄尸红;2 , 該微博已經(jīng)在本站存在 , 當前用戶未登錄 , 直接登錄成功痹扇;3 , 該微博未在本站注冊 , 但當前用戶已經(jīng)登錄并關(guān)聯(lián)的是另一個微博帳號 , 作何處理取決于是否允許綁定多個微博帳號;4 , 該微博未在本站注冊過 , 當前用戶已登錄 , 嘗試進行綁定操作;5 , 該微博已經(jīng)注冊 , 用戶又已使用該帳號登錄 , 為何他重復(fù)綁定自己 ; 6 , 該微博已經(jīng)在本站存在 , 但當前用戶已經(jīng)登錄并關(guān)聯(lián)的是另一個微博帳號 , 作何處理 ? 切換用戶或是報錯 ? (畫一個流程圖能更好描述這個問題) 這個問題與采用的數(shù)據(jù)結(jié)構(gòu)沒有關(guān)系 , 只是在做第三方帳號注冊登錄時遇到的各種情況 , 在此一并整理 ;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谣旁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滋早,老刑警劉巖榄审,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杆麸,居然都是意外死亡瘟判,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門角溃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拷获,“玉大人,你說我怎么就攤上這事减细〈夜希” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵未蝌,是天一觀的道長驮吱。 經(jīng)常有香客問我,道長萧吠,這世上最難降的妖魔是什么左冬? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮纸型,結(jié)果婚禮上拇砰,老公的妹妹穿的比我還像新娘。我一直安慰自己狰腌,他們只是感情好除破,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琼腔,像睡著了一般瑰枫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丹莲,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天光坝,我揣著相機與錄音尸诽,去河邊找鬼。 笑死盯另,一個胖子當著我的面吹牛性含,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播土铺,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼胶滋,長吁一口氣:“原來是場噩夢啊……” “哼板鬓!你這毒婦竟也來了悲敷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤俭令,失蹤者是張志新(化名)和其女友劉穎后德,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抄腔,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡瓢湃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赫蛇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绵患。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖悟耘,靈堂內(nèi)的尸體忽然破棺而出落蝙,到底是詐尸還是另有隱情,我是刑警寧澤暂幼,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布筏勒,位于F島的核電站,受9級特大地震影響旺嬉,放射性物質(zhì)發(fā)生泄漏管行。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一邪媳、第九天 我趴在偏房一處隱蔽的房頂上張望捐顷。 院中可真熱鬧,春花似錦雨效、人聲如沸套菜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逗柴。三九已至,卻和暖如春顿肺,著一層夾襖步出監(jiān)牢的瞬間戏溺,已是汗流浹背渣蜗。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旷祸,地道東北人耕拷。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像托享,于是被迫代替她去往敵國和親骚烧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容