多帐户登录设计

如今几乎大部分的App都支持使用多个第三方帐号进行登陆,如:微信、QQ、微博等,咱们把此称为多帐号统一登录。而这些帐号的表设计,流程设计相当重要,否则后续扩展性贼差。本文不提供任何代码实操,可是梳理一下博主根据我司帐号模块的设计,提供思路,仅供参考。html

1、 自建的登录体系

1.1 手机号登录注册

该设计的思路是每一个手机号对应一个用户,手机号为必填项。git

流程:github

  1. 首先输入手机号,而后发送到服务端。先判断该手机号是否存在帐号,若是没有,就会生成随机验证码,将手机号和验证码绑定到Redis中,并设置必定的过时时间(过时时间通常是5分钟,这就是咱们通常手机验证码的有效期),最后将验证码经过短信发送给用户。
  2. 用户接收到验证码后,在界面填写验证码以及密码等基础信息,而后将这些数据发送服务端。服务端收到后,先判断在Redis里面这个手机号对应的验证码是否一致,,失败就返回错误码,成功就给用户建立一个帐号和保存密码。
  3. 注册成功后,用户便可经过本身的手机号+密码进行登录。

问题:安全

  1. 用户体验差,须要完成获取验证码,填写验证码/密码/用户名等诸多的信息完成注册,而后才能使用;
  2. 容易遗忘密码,遗忘后,只能经过忘记密码来从新设置密码。

1.2 优化注册登录

该方案的思路是弱化密码的必填性,即不管用户是否注册过,可经过手机号 + 验证码 直接进行登录(保留手机号 + 密码登陆的方式)。服务器

流程:微信

  1. 输入手机号,而后发送到服务端。服务端生成随机验证码,将手机号和验证码绑定到Redis中,并设置必定的过时时间(过时时间通常是5分钟,这就是咱们通常手机验证码的有效期),最后将验证码经过短信发送给用户。
  2. 用户接收到验证码后,在界面只需填写收到的验证码,提交到服务端。服务端收到后,先判断在Redis里面这个手机号对应的验证码是否一致,失败就返回错误码,成功就直接登陆。若是是老用户,直接拉取用户信息;若是是新用户,则提示他能够完善用户信息(不强制)。
  3. 用户经过手机号 + 验证码登陆后,也可选择设置密码,而后就能够经过手机号 + 密码的方式登陆,即:密码是非必填项。

用户表设计:网络

id user_name user_password user_mobile state more
用户id 用户名 用户密码 手机号码 帐号状态 其余信息

1.3 引入第三方帐户方案

1.3.1 微博登陆

进入 Web2.0 时代 ,微博开放了第三方网站登陆, 产品说, 这个咱们得要, 加个用微博账号就能登陆咱们的App吧,并且得和咱们本身的用户表关联。ide

流程:post

  1. 客户端调用微博登陆的界面,进行输入用户名、密码,登陆成功后,会返回access_token,经过access_token调取API接口获取用户信息。
  2. 服务端经过用户信息在咱们用户表建立一个帐号,之后,该第三方帐号便可经过该微博帐号直接进行登录。

微博用户信息表设计:优化

id user_id uid access_token
主键id 用户id 微博惟一id 受权码

1.3.2 噩梦来临

紧接着, QQ又开放用户登陆了, 微信开放用户登陆了,网易开发用户登陆了。。。。。。一会儿要接入好多家第三方登陆了, 只能按照 “微博用户信息表” 新建一个表,重写一套各个第三方登陆。

2、 优化帐号体系

2.1 原帐号体系分析

  1. 自建登录体系:不管 手机号 + 密码 , 仍是 手机号 + 验证码 , 都是一种 用户信息+密码 的验证形式;
  2. 第三方登陆:也是用户信息+密码 的形式, 用户信息即第三方系统中的 ID(第三方系统中的惟一标识), 密码即 access_token, 只不过是一种有使用时效按期修改的密码。

2.2 新的帐号体系

2.2.1 数据表设计

用户基础信息表:

id nickname avatar more
用户id 昵称 头像 其余信息

用户受权信息表:

id user_id identity_type identifier credential
主键id 用户id 登陆类型(手机号/邮箱) 或第三方应用名称 (微信/微博等) 手机号/邮箱/第三方的惟一标识 密码凭证 (自建帐号的保存密码, 第三方的保存 token)

说明:

  1. 用户表分为 用户基础信息表 + 用户受权信息表
  2. 用户信息表不保存任何密码, 不保存任何登陆信息(如用户名, 手机号, 邮箱), 只留有昵称、头像等基础信息; 全部和受权相关,都放在用户信息受权表, 用户信息表和用户受权表是一对多的关系

2.2.2 登陆流程

  • 手机号 + 验证码

沿用以前的方案。

  • 邮箱/手机号 + 密码:

用户填写 邮箱/手机号 + 密码; 请求登陆的时候, 先判断类型, 如手机号登陆为例:

使用 type= 'phone' 结合 identifier= '手机号' 查找, 若有, 取出并判断 password_hash (密码)是否和该条目的 credential 相符, 相符则经过验证, 随后经过 user_id 获取用户信息;

  • 第三方登陆, 如微信登陆:

查询type= 'weixin' 结合 identifier= '微信 openId', 若是有记录, 则直接登陆成功, 并更新token; 假设与微信服务器通讯不被劫持的状况下无需判断凭证问题。

2.2.3 优缺点

优势:

  1. 登陆类型无限扩展, 新增登陆类型的开发成本显著下降;
  2. 原来条件下, 应用须要验证手机号是否已验证和邮箱是否已验证, 须要相对应多一个字段如 phone_verifiedemail_verified, 现在只要在 user_auths 表中增长一个统一的 verified 字段, 每种登陆方式均可以直观看到是否已验证状况;
  3. user_auths 添加相应的时间和 IP 地址, 就能够更加完整地跟踪用户的使用习惯, 好比:已经不使用微博登陆两年多, 已经绑定微信 300天;
  4. 若是你说邮箱和手机号就是用户信息的组成部分, users 表尽管拓展, users 表里依然有email , phone , 但他们仅仅做为“展现用途”,和昵称,头像或者性别这些属性没有本质区别;
  5. 可按需绑定任意数量的同类型登陆方式, 即一个用户能够绑定多个微信, 能够有多个邮箱, 能够有多个手机号。固然你也能够限制一种登陆方式只有一条记录;

缺点 :

  1. 用户同时存在邮箱、用户名、手机号等多种站内登陆方式时, 改密码时必须一块儿改, 不然就变成了邮箱 + 新密码, 手机号 + 旧密码均可以登陆, 确定是很诡异的状况;
  2. 代码量增长了, 有些状况下逻辑判断增长了, 难度增大了; 举个例子, 不管用户是否已登陆, 不管用户是否已注册过, 都是点击同一连接前往微博第三方受权后返回, 可能出现几种状况:
    1. 该微博在本站未注册过, 很好, 直接给他注册关联并登陆;
    2. 该微博已经在本站存在, 当前用户未登陆, 直接登陆成功;
    3. 该微博未在本站注册, 但当前用户已经登陆并关联的是另外一个微博账号, 做何处理取决因而否容许绑定多个微博账号;
    4. 该微博未在本站注册过, 当前用户已登陆, 尝试进行绑定操做;
    5. 该微博已经注册, 用户又已使用该账号登陆, 为什么他重复绑定本身;
    6. 该微博已经在本站存在, 但当前用户已经登陆并关联的是另外一个微博账号, 做何处理?

3、 一键登录

3.1 背景

回顾一下手机号 + 验证码 的登陆方式:

  1. 输入手机号、等待验证码短信、输入验证码、点击登陆。整个流程走完可能须要 20 秒以上,操做也比较繁琐;
  2. 它是依赖短信网络的,由于若是收不到短信,也就登陆不了了。
  3. 从安全角度考虑,还存在验证码泄漏的风险。若是有人知道了你的手机号,而且窃取到了验证码,那他也能登陆你的帐号了。

但回过头来想一下,为何咱们须要验证码?验证码的做用就是肯定这个手机号是你的,那除了使用短信,是否还有别的方式对手机号进行认证?

  1. 若是能获取到当前使用的手机号,就能对用户输入的号码进行验证了。但出于安全考虑,客户端是没法直接获取到手机号的,运营商则能够经过 SIM 卡数据查询到。
  2. 如今运营商已经开放了相关的能力,如今咱们能够在用户输入手机号后,经过调用运营商的接口,判断用户输入的手机号是否和本地号码一致。这样一来,用户就省去了等待验证码短信、输入验证码的过程,也不受短信网络的限制,简化了登陆流程。
  3. 但再进一步想,若是运营商能够把当前的号码直接返回给咱们,而不仅是用于验证,那用户连手机号都不须要填了。

这就是该部分的主角:一键登陆

3.2 本机号码认证

获取到当前手机使用的手机卡号,直接使用这个号码进行登陆,这就是一键登陆。

这种登陆方式的好处是显而易见的。它能够更方便、快捷地完成注册、登陆流程,将本来可能须要 20 秒的流程,缩短到了 2 秒左右,很大程度上提高了登陆的用户体验。

主要步骤以下:

  1. SDK 初始化:调用 SDK 的初始化方法,传入项目在平台上的 AppKey 和 AppSecret。
  2. 唤起受权页:调用 SDK 唤起受权接口。SDK 会先向运营商发起获取手机号掩码的请求,请求成功后跳转到受权页。受权页会显示手机号掩码以及运营商协议给用户确认。
  3. 赞成受权并登陆:用户赞成相关协议,点击受权页面的登陆按钮,SDK 会请求本次取号的 token,请求成功后将 token 返回给客户端。
  4. 取号:将获取到的 token 发送到咱们本身的服务器,由服务器携带 token 调用运营商一键登陆的接口,调用成功就返回手机号码了。服务器用手机号进行登陆或注册操做,返回操做结果给客户端,完成一键登陆。

目前阿里云已经提供了该方式并可兼容三大运营商的号码,详见阿里云SDK

4、小结

博主看来,没有最好的方案,选择适用当前系统的设计便可。不要深究孰优孰劣,鞋合不合脚,只有脚知道。

技术交流

  1. 风尘博客:https://www.dustyblog.cn
  2. 风尘博客-掘金
  3. 风尘博客-博客园
  4. Github
  5. 公众号
    风尘博客
相关文章
相关标签/搜索