一、我想到的答案。
为什么不能用设备id?
接口调用,如果是网页,设备id是无法获取的。另外,设备id可以作假。
为什么不能用ip区分?
有些网络(某些校园网),对外就是一个ip。
用token区分设备有什么缺点?
同一台设备登录多次,会被当成多个不同的设备。实在想不到好的办法,故逻辑实现采用token区分设备。
逻辑实现如下:
方案1:用redis里的list,key存【用户id】,value存【登录token】列表。用redis里的string,key存【登录token】,value存【登录时间】。30天免登,string中value值是否是30天以前,如果是30天以前,可以删掉string中的这个token,list中对应的token也需要删除。踢掉第1个,当用户数超过两个,踢掉list的第1个token,string中的token也需要删除。改密码,删除某个用户下的list以及string里的对应token。
方案2:用redis里的list,key存【用户id】,value存【登录token+时间】列表。
二、知乎答案: 使用 Redis 存储用户 ,登录的设备实现,利用 ZSET。
每个用户一个 ZSET(假设就是以用户 id 作为 ZSET 的 KEY),里面的 KEY 为设备 id,value 为登录时间戳。
1.当用户登录时,使用 lua 脚本(防止并发导致登录设备多于 2 个)检查设备:
ZSCORE 判断设备是否存在以及登录时间
如果存在:
ZADD就更新SCORE为当前时间戳
如果不存在:
ZCARD 用户id 获取当前用户有多少设备
如果设备数量 >= 2 则移除除了最后一个的其他设备(可以通过ZRANGE获取最后一个KEY,ZSCORE获取其分数之后ZREMRANGEBYSCORE删除小于这个分数的所有KEY)
ZADD设置设备id为KEY,当前时间戳为SCORE
设置ZSET过期时间为30天,减少30天内没有设备登录时检查登录态的判断消耗
2.当用户请求需要登录态后的 API,检查登录态时:
ZSCORE 判断设备是否存在以及登录时间
如果设备存在存在并且登录时间与当前时间间隔小于30天,则有效。
否则,登录态失效,需要重新登录
3.修改密码,所有设备下线:
删除这个ZSET
三、享学答案: 1.要能够识别不同的设备,比如移动设备的imei。
2.服务端需要有存储账号与设备的记录,以及客户端的ip及端口。
对于是否登出的检测有主动和被动两种方式。
3.服务端主动调用客户端登出。
3.1客户端可以开放清楚客户端cookie等登录信息的接口。
3.2.服务端在登录时存入设备与用户的记录,并且判断是否超出限制,如果超出限制则找出最早登录的客户端ip端口调用清楚客户端cookie的接口。
3.4.修改密码同理,调用所有已登录客户端的清楚cookie接口。
4.客户端主动检测登录是否已失效。
4.1服务端需要有检测登录有效性的接口。
4.2客户端在接到请求时主动调用服务器接口检测,根据响应判断当前登录状态,如果已失效则主动退出当前账号。
4.3登录超出限制或者修改密码时,服务端删除账号与设备的记录,在客户端调用登录有效性检测接口时查不到对应设备的记录则返回已失效。