解决方案产品经理技能提升架构设计

浅谈数据库用户表结构设计&第三方登录

2019-03-21  本文已影响246人  一个想简单的胖子

​ 说起用户表 , 大概是每个应用/网站立项动工考虑的第一件事情 ; 用户表结构的设计 , 算是整个后台架构的基石 ; 如果基石不稳 , 待到后面需求跟进了发现不能应付 , 回过头来反复修改用户表 , 要大大小小作改动的地方也不少 ; 与其如此 , 不妨设计用户表之初就考虑可拓展性 , 争取不需要太多额外代价的情况下一步到位 ;

先前设计

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)

​ 这个系统最大的特色就是 , 用户信息表不保存任何密码 , 不保存任何登录信息 (如用户名 , 手机号 , 邮箱) , 只留有昵称 , 头像等基础信息 ; 所有和授权相关 (且基本[前端]展示无关的) , 都放在用户信息授权表 , 用户信息表和用户授权表是一对多的关系 ; 说起来太抽象 , 表现如下 :

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 ; 假设与微信[服务器]通信不被劫持的情况下无需判断凭证问题 ;

优缺点``

通过这个表结构设计 , 使许多原来纠结的问题瞬间解决 , 说说优点 :

有利必有弊 , 说说缺点 :

上一篇 下一篇

猜你喜欢

热点阅读