淺談資料庫用戶表結構設計

来源:https://www.cnblogs.com/z937741304/archive/2019/04/02/10643229.html
-Advertisement-
Play Games

本篇文章並非原創,只是看到其中內容講的非常好,搬過來,還望海涵。 原文鏈接地址:http://wpceo.com/user-database-table-design/ 說起用戶表,大概是每個應用/網站立項動工(碼農們)考慮的第一件事情。用戶表結構的設計,算是整個後臺架構的基石。如果基石不穩,待到後 ...


本篇文章並非原創,只是看到其中內容講的非常好,搬過來,還望海涵。

原文鏈接地址:http://wpceo.com/user-database-table-design/

 

說起用戶表,大概是每個應用/網站立項動工(碼農們)考慮的第一件事情。用戶表結構的設計,算是整個後臺架構的基石。如果基石不穩,待到後面需求跟進了發現不能應付,回過頭來反覆修改用戶表,要大大小小作改動的地方也不少。與其如此,不妨設計用戶表之初就考慮可拓展性,爭取不需要太多額外代價的情況下一步到位。

先前設計

id
username
password

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

後來呢,隨著業務需求的拓展,要加個用戶狀態 status 判斷用戶是否被封禁,註冊時間和註冊IP地址、上次登錄時間和IP地址備查(並衍生出登錄記錄表,用來判斷是否異地登錄等,在此不表),用戶角色/許可權 role (又衍生出用戶角色許可權關係,還是另文討論),業務也需要個人的個人信息如真實姓名、地址等也一股腦往上添加,現在形成了一個很完整的用戶關係表。

id
username
password
realname
address

status
role
register_time
register_ip
login_time
login_ip

現在問題來了,進入Web2.0時代,微博開放了第三方網站登錄,用微博帳號就能登錄我們的網站,老闆說,這個我們得要。加個微博用戶登錄表吧,當然,得和我們自己的用戶表關聯,這個微博用戶信息表如下:

id 自增ID
user_id 關聯本站用戶ID
uid 微博唯一ID
access_token
access_expire

這還不算完,QQ又開放用戶登錄了,一下子要接入好多家第三方登錄了,只能就著“微博用戶信息表”繼續加類型加判斷,如果是每個第三方登錄都新建一個表,肯定會瘋的。

時代變了,進入了移動互聯網時代,怎麼也得支持個手機號登錄吧?所以現在每家標配都是:用戶名/郵箱/手機號登錄,外加一系列微博、微信等第三方登錄。表結構如下:

用戶表
id
username
email
phone

用戶第三方登錄表
id
user_id
app_type
app_user_id
access_token

用戶在輸入框輸入用戶名/郵箱/手機號和密碼之後,後臺判斷是郵箱、手機號或是用戶名,再根據條件查詢是否為特定用戶。

這個表結構能夠承載未來一段時間的業務需求了。如果說某天冒出了一個新的登錄方式,比如身份證號登錄,怎麼辦?繼續在用戶表加欄位?我覺得有更好的選擇。

改進版

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

用戶基礎信息表 users
id
nickname
avatar

用戶授權信息表 user_auths
id
user_id
identity_type 登錄類型(手機號 郵箱 用戶名)或第三方應用名稱(微信 微博等)
identifier 標識(手機號 郵箱 用戶名或第三方應用的唯一標識)
credential 密碼憑證(站內的保存密碼,站外的不保存或保存token)

這個系統最大的特色就是,用戶信息表不保存任何密碼,不保存任何登錄信息(如用戶名、手機號、郵箱),只留有昵稱、頭像等基礎信息。所有和授權相關(且基本前端展示無關的),都放在用戶信息授權表,用戶信息表和用戶授權表是一對多的關係。說起來太抽象,show me the code.

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|[email protected]|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|

說說具體處理,用戶發來郵箱/用戶名/手機號和密碼請求登錄的時候,依然是先判斷類型,以某用戶使用了手機號登錄為例,使用 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。假設與微信伺服器通信不被劫持的情況下無需判斷憑證問題。

通過這個表結構設計,使許多原來糾結的問題瞬間解決,說說優點吧

一,站內登錄類型無限拓展,代碼改動小。如果真要支持身份證登錄了,只要少許幾處改動,無需修改表結構。

二,第三方登錄類型可用工場模式批量拓展,新增第三方登錄類型的開發成本降到最低。

三,原來條件下,應用需要驗證手機號是否已驗證和郵箱是否已驗證,需要相對應多一個欄位如 phone_verified 和 email_verified,如今只要在user_auths表中增加一個統一的verified欄位,每種登錄方式都可以直觀看到是否已驗證情況。基於信任第三方登錄的數據準確性,預設第三方登錄都是已驗證。如果用戶修改登錄手機號或登錄郵箱,也能清晰跟蹤每一步的完成度。

四,可按需綁定任意數量的同類型登錄方式,即一個用戶可以綁定多個微信,可以有多個郵箱,可以有多個手機號,是不是很贊?當然你也可以限制一種登錄方式只有一條記錄。

五,在user_auths添加相應的時間和IP地址,就可以更加完整地跟蹤用戶的使用習慣,比如,已經不使用微博登錄兩年多,已經綁定微信300天

六,即使完全使用第三方帳號登錄,可在前端做到“無需註冊本站帳號”的效果。過去許多網站雖然支持第三方帳號登錄,但出於留存用戶等原因,第一次微博登錄回來,讓你再填寫一套他們網站的郵箱、密碼等信息,也就失去了微博登錄的最大意義。從技術上說,原有的結構導致除了在微博用戶表建立一個條目外,必須在用戶表建立一條對應的條目,而且一般情況下不能讓用戶表裡的郵箱或者用戶名和密碼留空。用戶體驗好的,郵箱自動生成 微博[email protected] ,密碼則隨機生成。至於體驗不好的,只能說早知道還不如不用微博登錄呢!現在呢,我們的這個用戶表結構則完全沒有這樣的困擾,只要微博提供的昵稱和頭像地址就可以生成這個用戶,再關聯他的微博登錄記錄。而且我們的表結構意味著,用戶可以解除他的所有登錄方式,於是這個賬戶變徹底變成了沒法登錄的僵屍(解決辦法是在代碼裡加一個限制,至少保留一條user_auths的記錄)。如果你非得得到用戶的郵箱,那麼每次登錄的時候看到他不存在一條identify_type為email的記錄,則彈窗彈死他,讓他趕快填郵箱,否則啥都別乾。

七,提升了邏輯思維能力。抽象出事物本質是碼農必備職業素養,通過對用戶表結構的學習研究,提高了鄙人的各方面技能,從此寫代碼一路順風順水…

八,如果你說郵箱和手機號就是用戶信息的組成部分,他們依然需要體現在users表中作為前端展示?沒問題,users表儘管拓展,users表裡依然有email,phone,但他們僅僅作為“展示用途”,和昵稱、頭像、或者性別這些屬性沒有本質區別。在用戶信息表與用戶授權登錄拆分後,用戶信息表可以隨時增加任意欄位,加星座,加生日,都沒問題,只需要在前端展示時多幾個輸入框,錄入時多幾行代碼,與用戶登錄相關的問題做到最大程度解耦。

有利必有弊,說說缺點。

一,原先的用戶判斷由1次SQL變成2次SQL請求。

二,用戶同時存在郵箱、用戶名、手機號等多種站內登錄方式時,改密碼時必須一起改,否則就變成了郵箱+新密碼,手機號+舊密碼訪問了,肯定是很詭異的情況。如果考慮到這一點,又要在user_auths表中新增一個表示站內登錄方式或第三方登錄方式的標識欄位。

三,代碼量增加了,有些情況下邏輯判斷增加了,難度增大了。舉個例子,無論用戶是否已登錄,無論用戶是否已註冊過,都是點擊同一鏈接前往微博第三方授權後返回,可能出現幾種情況:1,該微博在本站未註冊過,很好,直接給他註冊關聯並登錄;2,該微博已經在本站存在,當前用戶未登錄,直接登錄成功;3,該微博未在本站註冊,但當前用戶已經登錄並關聯的是另一個微博帳號,作何處理取決於是否允許綁定多個微博帳號;4,該微博未在本站註冊過,當前用戶已登錄,嘗試進行綁定操作;5,該微博已經註冊,用戶又已使用該帳號登錄,為何他重覆綁定自己- -. 6,該微博已經在本站存在,但當前用戶已經登錄並關聯的是另一個微博帳號,作何處理?切換用戶或是報錯?(畫一個流程圖能更好描述這個問題)這個問題與採用的數據結構沒有關係,只是在做第三方帳號註冊登錄時遇到的各種情況,在此一併整理。

再次感謝 wpceo (文章作者)的分享。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • armv8 1.前言 本文的主要內容來源於ARMV8白皮書v5,對ARMV8做一個概述。包含如下的內容: 首先從背景談起,講述ARM的發展歷程; 之後介紹ARMV8體繫結構的基本特征; 介紹A64指令集 介紹異常級別 介紹記憶體管理單元 介紹編程寄存器 介紹DEBUG相關 ARMV8生態系統的演化 2 ...
  • 問題描述: centos7,偽分佈模式下,啟動datanode後,通過JPS查看發現沒有相關進程,在日誌文件里也沒有任何提示。通過百度,網上一堆說什麼vesion 的ID不一致,不能解決我的問題。 經過搜索,https://community.hortonworks.com/questions/69 ...
  • 系統信息 arch 顯示機器的處理器架構(1) uname -m 顯示機器的處理器架構(2) uname -r 顯示正在使用的內核版本 dmidecode -q 顯示硬體系統部件 - (SMBIOS / DMI) hdparm -i /dev/hda 羅列一個磁碟的架構特性 hdparm -tT / ...
  • 1.安裝DHCP伺服器角色,這樣在netsh下才會有dhcp上下文 2.編寫配置dhcp的腳本 從命令行運行netsh有兩種語法: 比如要獲取已經配置的網路介面列表 1.寫全 其中:-r RemoteComputerName 是指定要操作的遠程主機或本機的電腦名,interface ipv4 是n ...
  • shutdown shutdown 此命令用來安全關閉或重啟Linux系統,系統在關閉之前會通知所有的登錄用戶,系統即將關閉,此時所有新用戶都不可以登錄。 以下截取man手冊的內容(man shutdown): NAME shutdown - bring the system down SYNOPS ...
  • 從mysql資料庫中導出正常資料庫的腳本語句,而後使用腳本語句創建資料庫的過程中,執行語句提示Can't Create Table 'XXX' erro150的錯誤,語句執行中斷,創建table失敗,仔細分析相關語句發現導致此錯誤的原因為創建的外鍵和關聯的表的主鍵類型不匹配。 仔細查看被執行的語句, ...
  • snapshot其實就是一組metadata信息的集合,它可以讓管理員將表恢復到以前的一個狀態。snapshot並不是一份拷貝,它只是一個文件名的列表,並不拷貝數據。一個全的snapshot恢復以為著你可以回滾到原來的表schema和創建snapshot之前的數據。 應用場景: 1獲取:該操作嘗試從 ...
  • [20190402]Library Cache mutex.txt1.環境:SCOTT@book> @ ver1PORT_STRING VERSION BANNER x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Editi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...