个人随笔
目录
架构设计学习:用户登录注册功能相关的设计和注意事项
2025-05-28 21:49:41

几乎每个系统都会设计用户方面的功能,比如登录注册这些,那么作为一个用户系统或者说用户功能在设计上有哪些注意事项?下面大概简单的列举一下。

一、用户数据的存储

1、根据用户数据量来设计

如果你的用户量不大,那么一个库一个表就可以了,这种实现起来就很简单,但是假设你的用户两很大,可能你需要进行分表分库,如果后面大到分表分库都搞不定了,比如你的服务器都在北京,所有数据都放北京,那么用户在广州访问可能就会有点延时,那么可能你的用户数据需要存储在不同地域。

但是虽然数据是存储在不同的地域,最终还是需要数据每个地域都有一份相同的,这样不仅仅可以做异地多活,还可以保证注册的时候直接查询是否存在。查询的时候也会很方便,不用多个地域去查询。

2、如果是存在不同的地方,那么怎么保证同一个用户重复注册?

用户用手机号A在北京注册,让后用户手机号A又在广州注册(假设北京注册成功,用户坐飞机回来广州进行注册,刚好北京的注册结果因为一些原因没有来得及同步到广州)怎么办?

有些人说用缓存?注册成功后放redis里面,广州查询redis有就成功不去注册了,这个方法也不是不可以,只不过,本来搞成异地就是为了速度,为了分开,现在又搞这样弄成一个缓存,感觉得不偿失,并且用户量大的话,你缓存也扛不住,还浪费资源,毕竟缓存也是钱啊!

那么有什么办法呢,其实可以进行二次查询,也就是当用户在广州注册的时候,如果广州库里没有,那么主动调用北京的接口查询下是否有。这样就解决了。

3、数据一致性怎么搞?

按上面说的,如果用户同时注册怎么办,就是假设张三和王五同时一个在北京一个在广州用同一个手机号注册,因为独立的事物,此时不管是北京去广州查询还是广州去北京查询都是没有注册的,最后就会导致有两条记录,怎么办?

有些人说用分布式缓存,比如在redis搞个自增(incr),当然也可以,不过这又回到了我上面说的问题。

有些人说用验证码,这个到是可以,毕竟发验证码正常来说我们都会在同一个能力中心操作的,所以用户二次获取验证码就会导致第一次失效。但是假设我们没有验证码怎么办,或者发验证码也是北京广州独立部署的怎么办?

我们可以用一个兜底方案,最终一致性,用户合并,毕竟我们用了“二次查询”的方法,这种并发的用户应该几乎不会出现了,但是假设系统问题,或者就是出现了,我们在数据最终同步的时候,需要进行用户合并,选择毕竟早或则比较晚的用户自动合并,这个要看你具体的业务逻辑,是否需要只保留一个用户的业务数据或者合并业务数据,或者通知用户自行选择触发合并,这些要具体问题具体分析。

二、用户数据的隐私性和安全

在很多业务系统中,特别是银行这些系统,对用户数据的隐私性和安全性要求比较高,比如只能密文存储用户的手机号这些。那么我们也会遇到一些问题。

1、存储

正常大都数公司的用户数据比如手机号身份证都是明文存储在数据库中的,但是如果要求比较高,那么可能需要密文存储,此时我们可以用对称加密或者非对称加密。

但是密文存储的话对搜素就不友好了,如果是精确匹配搜索还好,可以对查询条件先按相同的算法加密再查询,但是如果是模糊搜索呢?

有些人可能会说存储两个字段,一个密文一个明文,那这个密文其实没太大意义,只是虚晃一枪而已,其实办法有两个,比如身份证,我们可以在业务上要求模糊搜索只能根据身份证后四位或者手机号后四位模糊搜索,那么我们的加密就只加密前面的一定位数,后面四位不加密。或者后面四位独立处理重新加密存储在新的字段。这样也是先了伪模糊搜索。

2、传递

如果用户数据需要进行传递,也就是要调用接口传递给别人,那么怎么办呢,这里最简单的肯定是进行加密,跟对方约定一个加密密钥,进行加密即可,但是为了防止被串改,最好再加个签名。这样别人就看不到也改不了了。毕竟就算加密后的数据,中间人可以直接随机修改二进制代码,也会导致内容变化,或者根据一些加密算法的逻辑,直接替换相应的加密块,随意签名必不可少。

3、使用

我们在使用数据的时候,主要是要注意sql注入和横向越权的问题,sql注入很好解决,采用预编译即可,横向越权比如根据别人的订单号 查询别人的订单信息,这种,需要在设计上考虑清楚。

三、怎么防止恶意注册

为了防止别人用脚本批量注册,那么唯有提高注册的门槛,比如你的系统需要短信验证码的,那么就校验用户短信验证码,如果需要实名的,那么就需要用户先实名,或者借助第三方登录来确定身份。

但是假设你的系统不需要任何校验,用户输入用户密码就可以注册怎么办?那就通过图像验证码,限制ip等这些稍微提高下注册门槛。更胜者如果业务允许,可以考虑人工审核。

四、用户登录后怎么认证

1、sessionid

以前前后端不分离的话,我们采用的是sessionid,其实原理很简单,用户注册成功,后台会根据sessionid为 key把用户信息放入缓存中,然后返回sessionid,浏览器会帮我们在下次请求中把sesionid放到请求头,我们后台就可以根据sessionid来获取用户的登录信息了。

2、token

最近流行的都是前后端分离的模式,所以通常用token,也就是用户登录成功后,我们生成一个token,把用户的信息放入缓存比如redis中,然后把token返回,后面每次请求我们都主动把token放请求头带过来,后台根据token去查询是否登录。

3、失效的问题

正常我们的sessionid都是30分钟有效,我们的token也可以设置有效期,比如redis设置30分钟过期,如果过期了,我们可以让用户重新登录或者在登录成功后返回一个刷新token,根据刷新token重新获取token这些。如果我们没有redis也可以用JWT,JWT生成的token里面有有效期,毕竟进行了签名,所以这个有效期用户也不能串改。不过用JWT也会面临续期的问题,也可以根据刷新token的思路实现即可。

token也可能泄露出去,此时我们也可以绑定客户端ip,一定时间内入股用户ip有变化则强行让token失效。

用token的好处是,我们可以后台控制某一个token失效,也可以冗余一点,把登录用户的token跟用户信息做个存储,这样后台就可以根据用户找到登录的token实现踢人的逻辑。

五、认证共享的问题

假设我们的后台服务器是多个节点,用户在节点A获取了sessionid或者token,第二次请求到节点B怎么办?

我们可以借助一些中间件进行session在节点之间的共享,或者用统一的缓存来存储。当然JWT反而不会存在需要共享的场景,毕竟是否失效直接就在JWT中。

六、用户系统的开放平台

一般用户系统都是内部用的,很少会做成开放平台,毕竟没有公司愿意把自己的用户信息共享出去,除非为了钱,如果公司的登录注册接口需要提供给第三方用要怎么搞?

1、设计API

肯定要先设计API,比如登录和注册接口

2、授权

给第三方调用方appKey和secrect

3、收费

最终目标肯定是收费啊,所以我们可以要求每次调用我们的接口都带上appKey,然后根据调用次数来收费和控制。

4、提供开发文档和sdk

当然要提供友好的开放文档和sdk给第三方。

六、拓展

假设我们系统需要有用户关系,比如好友、粉丝、关注这些,那要怎么设计表呢?

关键一点是关系表,当然如果你的系统体量小,你用一张表也可以实现,最多加个字段类型,比如这个是关注关系,这个是好友关系,这个是粉丝关系,但是这样会导致这个表的数据量太大了。

所以好一点的做法就是设计如下几个表

1、用户表

存储用户的基本信息,包括用户ID,昵称,头像,性别,年龄

2、好友关系表

存储好友关系,包括好友关系D,用户ID和好友用户ID。

3、关注关系表

存储用户的关注关系,包括关注关系ID,用户ID和关注对象的用户ID

4、粉丝关系表

存储用户的粉丝关系,包括粉丝关系ID,用户ID和粉丝用户ID。

这样业务逻辑处理上来会清晰简单很多,后续数据量大了也可以进行分库分表,加缓存这些。

 6

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2