浅谈数据库用户表结构设计

本篇文章并不是原创,只是看到其中内容讲的很是好,搬过来,还望海涵。前端

原文连接地址:http://wpceo.com/user-database-table-design/服务器

 

提及用户表,大概是每一个应用/网站立项动工(码农们)考虑的第一件事情。用户表结构的设计,算是整个后台架构的基石。若是基石不稳,待到后面需求跟进了发现不能应付,回过头来反复修改用户表,要大大小小做改动的地方也很多。与其如此,不妨设计用户表之初就考虑可拓展性,争取不须要太多额外代价的状况下一步到位。微信

先前设计

id
username
password数据结构

用户名加上密码,解决简单需求,留个id做为其余表的外键。固然,那时候密码还多是明文存储,好点的知道md5。架构

后来呢,随着业务需求的拓展,要加个用户状态 status 判断用户是否被封禁,注册时间和注册IP地址、上次登陆时间和IP地址备查(并衍生出登陆记录表,用来判断是否异地登陆等,在此不表),用户角色/权限 role (又衍生出用户角色权限关系,仍是另文讨论),业务也须要我的的我的信息如真实姓名、地址等也一股脑往上添加,如今造成了一个很完整的用户关系表。app

id
username
password
realname
address

status
role
register_time
register_ip
login_time
login_ipide

如今问题来了,进入Web2.0时代,微博开放了第三方网站登陆,用微博账号就能登陆咱们的网站,老板说,这个咱们得要。加个微博用户登陆表吧,固然,得和咱们本身的用户表关联,这个微博用户信息表以下:学习

id 自增ID
user_id 关联本站用户ID
uid 微博惟一ID
access_token
access_expire网站

这还不算完,QQ又开放用户登陆了,一会儿要接入好多家第三方登陆了,只能就着“微博用户信息表”继续加类型加判断,若是是每一个第三方登陆都新建一个表,确定会疯的。ui

时代变了,进入了移动互联网时代,怎么也得支持个手机号登陆吧?因此如今每家标配都是:用户名/邮箱/手机号登陆,外加一系列微博、微信等第三方登陆。表结构以下:

用户表
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|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|

说说具体处理,用户发来邮箱/用户名/手机号和密码请求登陆的时候,依然是先判断类型,以某用户使用了手机号登陆为例,使用 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天

六,即便彻底使用第三方账号登陆,可在前端作到“无需注册本站账号”的效果。过去许多网站虽然支持第三方账号登陆,但出于留存用户等缘由,第一次微博登陆回来,让你再填写一套他们网站的邮箱、密码等信息,也就失去了微博登陆的最大意义。从技术上说,原有的结构致使除了在微博用户表创建一个条目外,必须在用户表创建一条对应的条目,并且通常状况下不能让用户表里的邮箱或者用户名和密码留空。用户体验好的,邮箱自动生成 微博ID@id.weibo.sina.com ,密码则随机生成。至于体验很差的,只能说早知道还不如不用微博登陆呢!如今呢,咱们的这个用户表结构则彻底没有这样的困扰,只要微博提供的昵称和头像地址就能够生成这个用户,再关联他的微博登陆记录。并且咱们的表结构意味着,用户能够解除他的全部登陆方式,因而这个帐户变完全变成了无法登陆的僵尸(解决办法是在代码里加一个限制,至少保留一条user_auths的记录)。若是你非得获得用户的邮箱,那么每次登陆的时候看到他不存在一条identify_type为email的记录,则弹窗弹死他,让他赶快填邮箱,不然啥都别干。

七,提高了逻辑思惟能力。抽象出事物本质是码农必备职业素养,经过对用户表结构的学习研究,提升了鄙人的各方面技能,今后写代码一帆风顺顺水…

八,若是你说邮箱和手机号就是用户信息的组成部分,他们依然须要体如今users表中做为前端展现?没问题,users表尽管拓展,users表里依然有email,phone,但他们仅仅做为“展现用途”,和昵称、头像、或者性别这些属性没有本质区别。在用户信息表与用户受权登陆拆分后,用户信息表能够随时增长任意字段,加星座,加生日,都没问题,只须要在前端展现时多几个输入框,录入时多几行代码,与用户登陆相关的问题作到最大程度解耦。

有利必有弊,说说缺点。

一,原先的用户判断由1次SQL变成2次SQL请求。

二,用户同时存在邮箱、用户名、手机号等多种站内登陆方式时,改密码时必须一块儿改,不然就变成了邮箱+新密码,手机号+旧密码访问了,确定是很诡异的状况。若是考虑到这一点,又要在user_auths表中新增一个表示站内登陆方式或第三方登陆方式的标识字段。

三,代码量增长了,有些状况下逻辑判断增长了,难度增大了。举个例子,不管用户是否已登陆,不管用户是否已注册过,都是点击同一连接前往微博第三方受权后返回,可能出现几种状况:1,该微博在本站未注册过,很好,直接给他注册关联并登陆;2,该微博已经在本站存在,当前用户未登陆,直接登陆成功;3,该微博未在本站注册,但当前用户已经登陆并关联的是另外一个微博账号,做何处理取决因而否容许绑定多个微博账号;4,该微博未在本站注册过,当前用户已登陆,尝试进行绑定操做;5,该微博已经注册,用户又已使用该账号登陆,为什么他重复绑定本身- -. 6,该微博已经在本站存在,但当前用户已经登陆并关联的是另外一个微博账号,做何处理?切换用户或是报错?(画一个流程图能更好描述这个问题)这个问题与采用的数据结构没有关系,只是在作第三方账号注册登陆时遇到的各类状况,在此一并整理。

再次感谢 wpceo (文章做者)的分享。

相关文章
相关标签/搜索