calidion.github.io icon indicating copy to clipboard operation
calidion.github.io copied to clipboard

多账号体系下用户系统的设计

Open calidion opened this issue 8 years ago • 10 comments

随着用户的社交关系越来越复杂,如何很好的管理用户的社交帐号成了大多数开发人员的头痛的事情。 下面我想探讨一下多账号体系下用户系统的设计。

要点

对于多帐号系统问题的关键在于以下几点:

  1. 为异构的社交帐号建立帐号体系
  2. 将异构的社交帐号统一到一个唯一的用户系统中来
  3. 解决同一个用户建立了多个用户帐号后的合并问题

解决方案

基于以上几个核心诉求,我们可以得到以下几个解决方案

1. 为支持的社交网络建立用户体系,从而可以得到各类用户表,比如

oauth-weibo, oauth-weixin, oauth-facebook,oaut- github. 由于这些社交网络的数据并不统一,所以不同的表格的格式不尽相同。 所以我们称之为异构数据。

2. 建立一张本地用户总表,用于存放唯一的用户数据

3. 为社交网络与本地用户建立对应关系,

建立如下的类型表:

本地用户唯一ID 社交网络类型 社交网络唯一ID
1112 weibo 20
5111 qq 20
6000 weixin 10
6000 qq 300

也就是对于不同的weixin与qq用户,他们可能会共享一个本地唯一ID 6000

4. 如果用户通过社交网络登录时并没有创建帐号,可以自动创建一个唯一的用户ID

5. 合并帐号

很多时候用户可能会忘记他原来已经注册过帐号,所以同一用户会通过不同的登录方式登录进来。 到他发现自己两个帐号都在,并且不能统一到一个帐号下时一定很沮丧。 所以这个时候,你可以做一次帐号统一的工作。 具体很简单,将较完一点的唯一用户ID合并到较上一点的唯一用户ID上。 同时更新所有采用唯一用户ID的地方的信息,如果出现重复信息,删除较晚的用户信息。 为了安全起见,这些数据也可以放到固定的数据表里。

6. 这样不管用户出现过多少次重复,作一次合并就解决这些的问题。

calidion avatar Mar 04 '16 18:03 calidion

请教一下唯一用户id规则怎么设定? 毕竟是不同社交账号,对应的id也不同

soakit avatar Mar 31 '16 15:03 soakit

@soakit 不同的id放入不同的表里, 用一张用户表统一起来即可。

calidion avatar Apr 01 '16 04:04 calidion

用户系统,主要分为账号体系和用户信息两大类。账号体系包括,登陆验证、注册、第三方授权、以及权限管理。用户信息包括,用户地理位置、用户属性、用户设备信息、还有用户日志信息。本文会介绍用户系统的具体落地方案。

登陆验证

在一般项目账号体系中,一般会要求支持手机、邮箱、账号、QQ、微信、微博实现登陆。后面三种方式都是基于第三方授权后,完成的身份验证。手机、邮箱、账号则是相对传统的登录方式。

用户身份与登录的授权方式是独立开的,即用户uid和登录方式是一对多的关系。举例来说,用户A在使用微博授权登陆后,服务端鉴别身份信息为uid=123。用户A下次使用微信登陆,服务端鉴别身份同样为uid=123。不存在同一用户A拥有多个账号信息的现象。

用户信息

用户信息,为便于扩展,分成两类。用户基础信息和用户拓展信息。基本信息用来保存用户的基本属性,年龄、性别、生日、头像、手机号码等。扩展信息,用来保存用户的设备信息或其他可扩展的内容。另外还有位置信息,这个可独立出来,也可合并到扩展信息中,根据自己的使用场景来定。

用户日志信息

日志信息,用来保存用户注册或者登陆行为的。另外会有一些修改密码或者修改重要信息的日志记录。

全局uid

建议不要使用表的主键作为用户ID,而是使用ID生成器(发号器)生成用户的唯一标示guid。当用户量急剧上升时,往往会采取分库分表的方法,然后通过将uid取余写到不同的表中。如果单纯的以某个表主键作为ID。会限制插入性能和增加业务复杂度,其次在分布式数据库中也无法保证ID唯一性。

全局ID生成,是有很多方案的。简单一点,可以采用redis自增属性,因为其具有原子性,在分布式坏境中,能保证ID的唯一性。另外还有其他的一些开源方案,可自行Google。

Access Token

与传统的Session相比,Access Token比较适合做RESTful Api开发。传统Web应用中,用户登陆后会写用户信息到cookie中,服务端通过Session就能得到用户的身份。

Access Token的是OAuth2.0中用户经过授权后,返回调用API的凭证。对于自己的应用来讲,用户在登录后,即返回accesstoken。在token有效期内可凭借此凭证,调用其他接口。对于accesstoken的刷新有两种方案,第一种每次用户重启app时,重新refresh。第二种,在调用周期内服务端发现access token可能过期时,返回新的token给客户端。

至于Access Token的生成,这个并没有规定,只要保证其唯一性即可。简单点,对用户uid和当前时间哈希得到新的Access Token,并设置过期时间。另外也可以采用JWT实现。

原文地址:http://gglinux.com/2017/03/31/user/

gglinux avatar Apr 05 '17 11:04 gglinux

合并账号这方面做得显然不是很合理

sowork avatar Jun 29 '18 01:06 sowork

合并账号不是仅仅合并用户表数据就好,所有设计到用户id的表都需要处理,如果遇到分库分表难度又更大。

sthe9 avatar Jul 30 '18 02:07 sthe9

这里讲的合并是一个最终的结果,过程如何处理不同的项目会有不同的方式。

但是如果一个用户合并后还存在多个用户ID,那么维护这些ID的成本将比合并的成本要高。

所以无论如何分库,分表了,你都需要统一ID。

除非你特别有资源,能够承担不合并ID的成本,那么不合并ID也不是不可以的。

所以分库,分表并不影响我所说的处理方式的合理性,正确性。同时也不影响其它方便处理的合理性。

我的处理方式只是一种合理的解决方案。

但是并不排除还存在其它正确的方案。

但是从简单性来讲,这种方案是相对比较简单的方案,也是一劳永逸的方案。

calidion avatar Jul 30 '18 05:07 calidion

合并不是一个好的方法,可以参考qq关联账号来想,只要让用户绑定账号即可,数据还是分布在两个账号,不冲突。 如果单纯的要去将两个账号数据合并,操作比较麻烦。

另外关于账户表设计,上面推荐的是一张主表,外加一张三方表,我提供另一种方式: 比如:添加机构、学校、老师这些角色进来,用户单独存放在各自的表中,用户根据(表名和表ID)来确定唯一用户即可

sowork avatar Jul 30 '18 05:07 sowork

如果你没有合并,显然各种操作的复杂度都会增加。

合并是一个时间点操作。

只要你的设计没有问题,合并完成后就不会有问题。

怎么会麻烦呢?

总比你以后搜索时因为帐户不同,搜索结果处理总是出错要简单多了。

同时QQ的帐户体系确实存在严重的问题,这一点阿里相比较而言要好很多。

阿里一个帐户基本上能将所有的服务走下来,QQ目前是不行。

这种不合并,不但会引起用户的不方便,更是会引起程序开发的不方便。

所以我不知道合并不好的说法怎么得出来的。

不能正常合并用户帐号,很显然是种设计缺陷。

calidion avatar Jul 30 '18 06:07 calidion

"更新所有采用唯一用户ID的地方的信息" 这个操作不好实现与拓展。 很多表都关联了userId。还可能分布在多个数据库、甚至多个系统。 比如用户的商品、用户登录日志在mysql中。用户发布的作品,用户操作记录在mongodb中,用户浏览记录在redis中,而且这些数据的插入更新在不同的系统,有可能是java在操作商品数据库,有可能pyhon操作日志数据库,node操作博客数据库 然后以后还会新增需求,又会多一张关联用户id的表 这样合并起来,以后的拓展如何解决 在合并期间,分布式事务又如何解决 我现在这样的系统还能合并吗。。。

SongJiaxin95 avatar Aug 28 '20 10:08 SongJiaxin95

@SongJiaxin95

当你问这个问题的时候,说明你的能力需要提升了。

你这样的系统唯一要做的就是一开始就保持用户ID的唯一。

否则就需要做一次同步工作,不过这样的工作通常会以失败造终。

calidion avatar Aug 29 '20 15:08 calidion