背景
一般来说大型互联网公司会把授权和用户信息的逻辑放到一个应用中,而这个应用我们统一称为用户中心。
用户中心不关心具体的业务逻辑,只处理用户信息相关的管理及授权登录。当第三方应用需要登录的时候,会把用户的登录请求转发到用户中心处理,处理完毕后,返回给第三方应用,第三方应用根据对应的凭证登录到系统内部。
主要功能如下
用户登录与注册
基本信息查询与修改
系统内服务间会话信息共享接口
从功能来看,整个用户中心还是很简单单,不过其中的逻辑还挺复杂的,比如注册功能,就要分为手机注册与邮箱注册,手机要发送手机验证码,邮箱需要发送验证邮件,点击邮箱里面的链接跳转并进行后续注册流程,上面每步都需要业务上重新发送机制。登录方面要考虑单点登录、登录失败、找回密码、登录验证(图片验证、手机验证码验证[推荐])、黑白名单算法等。
功能介绍
用户登录
在互联网用户中心体系中,一般会支持手机、邮箱、帐号、三方登录。其中三方登录一般会接入 QQ、微信、微博这三种方式。
密码登录
1. 用户在浏览器端填写 username + password ,然后提交到服务端。
2. 服务端拿到用户提交的 username + password 验证。
3. 验证成功后,服务器返回请求,同时将 cookie 写到对应域。
上述流程中,大家肯定会考虑到密码的安全性,我们到底该怎么做才能防止密码被泄露?对称加密还是非对称加密? 如果是对称加密,客户端被黑客反编译,就能拿到密钥,那么所有用户的密码就会存在非常大的泄露风险?如果是非对称加密,私钥要放在哪里才能保证安全?
通用简单的解决方案: Https + MD5 + 随机盐
Https 我就不用在述说了,基本上 Chrome、Firfox 都对不是 Https 的站点进行安全提醒,所以 Https 该上的还是尽快上吧
那如果公司很穷,买不起 Https 证书咋办呢?那么只能在前端页面上做点文章。
由于前端代码暴露在浏览器上,我们只能采用不可逆的密码或者摘要算法,类是与 MD5 / Hash 算法 。如果高级的话,就采用随机 Salt 来提高攻击成本,针对不同用户,加入不同的 Salt,而不是固定盐的方式。使用这种方式的前提「目前对安全的要求不高」
那我们该如何验证密码?客户端端提交 MD5(password)密码。服务端通过 MD5 (Salt + MD5(passowrd))的逻辑来计算最终密码,同时 Salt 只会出现在服务端,且每个用户采用不同 Salt 的方式来生成。这一系列过程中,都没有接触到原始的用户密码,如果出现用户的密码被劫持的话,只会发生在用户在提交密码前截获,这个也就是为什么需要密码控件?
有时候登录加密会采用非对称加密方式,服务端提供有限次数调用的公钥接口。前端生成加密字段后在推送给后端。这样的设计就要根据实际情况调整公钥的生命期,时间越短越安全。不过考虑到网络环境等因素时间也不能太短(建议不要超过二分钟)。针对有可能被劫持的因素,可在后端做异地登录验证结合IP地址和手机验证码来实现进一步的安全验证。
三方登录
当用户以某种登录方式成功登录之后,我们能可以获取到对应 User 表中的用户基础信息,而登录操作只是为了认证用户这个过程,无论用本地密码验证还是第三方登录,以上过程本质上都是认证的形式。
所以用户的信息与登录的授权其实是独立开来的,即 uid 与 登录方式是一对多的关系。比如: 用户 A 使用「微信」登录,服务端认证身份后 uid = abc。而下一次用户 A 使用「微博」登录,同样服务端认证出来 uid = abc。
用户信息表(user_base)只存储用户 Profile 相关信息
id | name | city
----+------+-----------------
A1 | Tom | 上海
A2 | Jack | 背景
而本地密码验证可以当做一种授权方式,可以称为 local_auth 表
id | user_id | password
----+---------+----------
1 | A1 | qazwsx
2 | A2 | edcrfv
而通过微博登录就可以视作为另外一种登录方式,称为 weibo_auth 表
id | user_id | weibo_id | weibo_access_token | weibo_expires
----+---------+----------+--------------------+---------------
1 | A1 | W-qaz | xxxxxxxxxx | 604800
2 | A2 | W-wsx | xxxxxxxxxx | 604800
最后,如果还要增加一种登录方式的话,可以直接添加一直 xx_auth 表来存储用户认证信息,大大提高了我们授权方式的灵活性。
针对第三方授权登录,第三方往往会开放一些用户信息暴露的接口,针对系统需求来确定是否将信息保持到本地。
信息共享接口
针对用户的一些信息有时候需要暴露给系统内的其他服务,所有服务要提供必要的信息暴露接口。针对是对外暴露还是系统内暴露做不同的安全验证方式,可以采用Oauth2.0+jwt的方式来实现。结合信息安全等级和系统安全等级来决定采用是Oauth2.0还是jwt方式。
权限管理
有时候因为设计规模的原因需要把权限控制也放到用户中心一起维护,遇到这样的情况建议做好模块隔离这样方便后期拆分。权限控制是一个需要被高频率调用的服务。建议不要将涉及权限配置的信息暴露出了。只做权限验证。例如用户tom是否具有模块A的修改权限的验证,只需要传入用户信息和模块信息调用修改权限验证服务来验证是否具备修改权限。不要采用获取全局或者部分权限配置自己验证的方式。这样做就失去的权限管理的目的。
网友评论