现在几乎大部分都是 App 使用多个第三方账号进行登录,如:微信,QQ、微博等,我们称之为多账号统一登录。而且这些账号的表设计和流程设计非常重要,否则后续扩展性小偷就不好了。
本文不提供代码实际操作,而是梳理账号模块的设计,提供思路,仅供参考。不要喷大佬!(文章目录)
1.1 自建登陆系统1.1.1 手机号登录注册设计思路是每个手机号对应一个用户,手机号是必填项。
流程:
- 首先输入手机号码,然后发送到服务端。首先判断手机号码是否有账户。如果没有,将生成随机验证码,绑定手机号码和验证码 ==Redis== 在中间,设置一定的过期时间(过期时间一般为5分钟,这是我们一般手机验证码的有效期),最后通过短信将验证码发送给用户。
- 用户收到验证码后,在界面上填写验证码、密码等基本信息,然后将这些数据发送到服务器。收到服务器后,首先判断 ==Redis== 手机号码对应的验证码是否一致,失败后返回错误码,成功为用户创建帐户和保存密码。
- 注册成功后,用户可以通过自己 ==手机号码+密码== 进行登陆。
问题:
用户体验差,需要完成获取验证码、填写验证码/密码/用户名等信息才能完成注册;密码很容易忘记。忘记后,只能通过忘记密码重新设置密码。
1.1.2 优化注册登录该方案的思路是削弱密码的必填性,即无论用户是否注册,都可以通过 ==手机号+验证码== 直接登录(保留) ==手机号码+密码== 登录方式)。
流程:
- 输入手机号码,然后发送到服务端。服务端生成随机验证码,绑定手机号码和验证码 ==Redis== 在中间,设置一定的过期时间(过期时间一般为5分钟,这是我们一般手机验证码的有效期),最后通过短信将验证码发送给用户。
- 用户收到验证码后,只需在界面上填写验证码并提交给服务端。服务端收到后,首先判断 ==Redis== 手机号码对应的验证码是否一致,如果失败,返回错误代码,并直接登录成功。如果是老用户,直接获取用户信息;如果是新用户,提示他可以改进用户信息(不是强制性的)。
- 用户通过 ==手机号+验证码== 登录后,您还可以选择设置密码,然后通过 ==手机号码+密码== 登录方式,即密码是非必填项。
用户表设计:
进入 ==Web2.0== 时代 ,微博开通了第三方网站登录, 产品说, 我们想要这个,加个微博账号就可以登录我们了 ==App== ,它必须与我们自己的用户表相关联。
流程:
- 客户端调用微博登录界面输入用户名和密码。登录成功后,将返回 ==access_token== ,通过 ==access_token== 调取 ==API== 接口获取用户信息。
- 服务端通过用户信息在我们的用户表中创建一个账户,然后第三方账户可以通过微博账户直接登录。
微博用户信息表设计:
紧接着, QQ再次打开用户登录, 微信开放用户登录,网易开放用户登录。。。一下子就要接入很多第三方登录, 只能按照 “微博用户信息表” 重写一套每个第三方登录的新表。
2.1 2.2优化账号系统.1 分析原账号系统- 自建登陆系统:无论 ==手机号码+密码== , 还是 ==手机号+验证码== , 都是一种 ==用户信息+密码== 验证形式;
- 第三方登录:也是 ==用户信息+密码== 的形式, 用户信息是第三方系统中的用户信息 ==ID== (第三方系统中唯一的标识), 密码即==access_token== , 它只是一种定期修改使用时间限制的密码。
用户基本信息表:用户授权信息表:
说明:
- 用户表分为 ==用户基本信息表== + ==用户授权信息表==;
- 用户信息表不保存任何密码, 不保存任何登录信息(如用户名, 手机号, 邮箱), 只有昵称、头像等基本信息;所有与授权有关的信息都放在用户信息授权表中, ==用户信息表和用户授权表是一对多的关系== 。
- ==手机号+验证码==
遵循以前的方案。
- ==邮箱/手机号+密码==:
用户填写 ==邮箱/手机号+密码==; 请求登录时, 先判断类型, 以手机号登录为例:
使用 ==type='phone'== 结合 ==identifier='手机号'== 查找, 如有, 取出并判断 ==password_hash== (密码)是否符合本条目的目的 ==credential== 相符, 一致性通过验证, 随后通过 ==user_id== 获取用户信息;
- 第三方登录, 如微信登录:
查询 ==type='weixin'== 结合 ==identifier='微信 openId'==, 如果有记录, 直接登录成功, 并更新 ==token==; 假设与微信服务器通信不被劫持,则无需判断凭证问题。
2.2.3 优缺点优点:
- 无限扩展登录类型, 新登录类型的开发成本显著降低;
- 在原有条件下, 应用程序需要验证手机号码是否已经验证,邮箱是否已经验证, 需要相应多一个字段,例如 ==phone_verified== ==email_verified==, 如今只要在 ==用户授权信息表== 在表中增加一个统一 ==verified== 字段,每一种登录方式都能直观地看到是否已经验证;
- 在 ==用户授权信息表== 添加相应的时间和 ==IP== 地址, 您可以更完整地跟踪用户的使用习惯, 例如:已经两年多没有使用微博登录了, 微信已绑定300天;
- 假如你说邮箱和手机号码是用户信息的一部分, users 尽管表扩展, users 表中仍有email , phone ,但它们只作为“显示用途”,与昵称、头像或性别没有本质区别;
- 同类型的登录方式可以根据需要绑定任何数量, 即一个用户可以绑定多个微信, 可以有多个邮箱,可以有多个手机号码。当然,您也可以限制只有一个记录的登录方式;
缺点 :
- 当用户在电子邮件、用户名、手机号码等站内登录方式同时存在时, 更改密码时,必须一起更改, 否则就变成了 邮箱+新密码, 可以登录手机号+旧密码, 一定是很奇怪的情况;
- 代码量增加了, 在某些情况下,逻辑判断增加了, 难度增加; 举个例子, 无论用户是否登录, 不管用户是否注册过, 点击同一链接返回微博第三方授权后, 几种情况可能发生:
该微博未在本网站注册, 很好, 直接给他注册关联并登录;这个微博已经存在于这个网站上, 目前用户还没有登录, 直接登录成功;这个微博已经存在于这个网站上, 目前用户还没有登录, 直接登录成功;微博没有在本网站注册, 但是目前用户已经登录并关联了另一个微博账号, 做什么取决于是否允许绑定多个微博账号;微博没有在本网站注册, 目前,用户已登录, 尝试绑定操作;微博已经注册, 用户已使用该帐户登录, 为什么他反复绑定自己;这个微博已经存在于这个网站上了, 但是目前用户已经登录并关联了另一个微博账号, 作何处理?
3.1 一键登陆3.1.1 背景回顾一下 ==手机号+验证码== 登录方式:
- 输入手机号码,等待验证码短信,输入验证码,点击登录。整个过程可能需要完成 20 秒以上,操作繁琐;
- 它依赖于短信网络,因为如果你不能收到短信,你就不能登录。
- 从安全的角度来看,验证码泄漏的风险仍然存在。如果有人知道你的手机号码并窃取了验证码,他也可以登录你的账户。
但回想起来,为什么我们需要验证码?验证码的功能是确定手机号码是您的。除了使用短信,还有其他方法来验证手机号码吗?
- 如果您可以获得当前使用的手机号码,您可以验证用户输入的号码。但出于安全考虑,客户不能直接获得手机号码,运营商可以通过 查询SIM卡数据。
- 现在运营商已经开放了相关的能力,现在我们可以通过调用运营商的接口来判断用户输入的手机号码是否与当地号码一致。这样,用户就节省了等待验证码短信和输入验证码的过程,不受短信网络的限制,简化了登录过程。
- 但进一步考虑,如果运营商可以直接将当前号码返回给我们,而不仅仅是验证,用户甚至不需要填写手机号码。
这部分的主角是:==一键登录==。
3.2.2 本机号码认证获取当前手机使用的手机卡号码,直接使用此号码登录,即一键登录。
这种登录方式其优点是显而易见的。它可以更方便、更快地完成注册和登录流程,并且可能需要它 20 秒的过程缩短到了 2 大约几秒钟,大大提高了登录用户体验。
主要步骤如下:
- SDK 初始化:调用 SDK 在平台上引入项目的初始化方法 AppKey 和 AppSecret。
- 唤起授权页:调用 SDK 唤起授权界面。SDK将首先向运营商发起获取手机号码验证码的请求,并在请求成功后跳转到授权页面。授权页面将显示手机号码和运营商协议,以确认用户。
- 同意授权和登录:用户同意相关协议,点击授权页面的登录按钮,SDK 这次会要求取号的 token,请求成功后 token 返回给客户端。
- 取号:将获得的 token 发送到我们自己的服务器,由服务器携带 token调用运营商一键登录的接口,成功调用后返回手机号码。服务器使用手机号码登录或注册,并将操作结果返回给客户端,完成一键登录。
