JWT 如何实现一个账号只能同时在一个设备(端)登录

2019-04-10 16:10:22 +08:00
 imherer

初次尝试 JWT,发现一个账号生成多个 JWT token 后,只要在这些 token 还没过期前都是有效的

例如账号 A 在 15:30 分登录生成了 token0,有效时间为 1 小时,过了 5 分钟账号 A 再次登录生成了 token1 有效时间还是为 1 小时。 这时候 token0 和 token1 都是合法的? 我之前以为 token1 会把 token0 给刷新掉……


那么如何实现一个账号只能同时在一个设备(端)登录呢?想到了如下几种方式:


各位大佬有什么好方法吗?

11206 次点击
所在节点    程序员
19 条回复
noe132
2019-04-10 16:13:55 +08:00
直接用 session。
whileFalse
2019-04-10 16:14:44 +08:00
你需要 session。jwt 面向离线认证设计,其本就不准备支持吊销功能。

session 放内存或者缓存服务,不会对数据库造成压力。
aimerforreimu
2019-04-10 16:19:22 +08:00
jwt 设计的时候就有专门的使用场景的,你这样需求的话,用 session 比较合适,物尽其用是最吼的,没有必要强制用 jwt 的
hantsy
2019-04-10 19:33:04 +08:00
如果用 Spring, 可以使用 Spring Session ( 可以选择由 Redis 等存储), 除了实现传统 HTTP Session 接口外,,还是可以在应用之间共享,可以作为 API 安全方案,也适合于 microservice 架构.

https://github.com/hantsy/spring-microservice-sample#secures-microservice


如果自己实现,不管是什么语言,也可以尝试将 Token 写入 Redis,Redis 写入时可以可以设置 Timeout。
xuanbg
2019-04-10 20:18:20 +08:00
JWT 不支持的,自己撸一个吧。我的经验是把一些用户信息搞成一个对象放 Redis,生成的 Token 只包含令牌本身的 ID、用户 ID 和验证串就行了。这样服务端在验证 Token 的时候就很灵活了,可以轻松实现楼主的单设备登录需求。
freakxx
2019-04-10 23:56:23 +08:00
如果是 drf 那套的话,
login 的时候直接把 token 更新下就可以。


jwt 的过期和刷新的理念,当时用的时候觉得不太顺手,git 上面好像还有一个 issue 就是讨论这个问题。
kangzai50136
2019-04-11 05:15:12 +08:00
直接 spring session 吧,虽然我自己用 jwt+redis。我当初听说分布式的话 jwt+redis 比 session 好才选了 jwt。
whileFalse
2019-04-11 08:30:16 +08:00
@freakxx 过期和刷新概念的目的就是弥补 jwt 不支持服务端主动吊销的问题。
如果业务不需要主动吊销,直接签发无限时间或 99 年的 jwt 即可。
huangdayu
2019-04-11 09:28:02 +08:00
存 jwt 的 id,对 id 进行操作,删除则是吊销
zhenjiachen
2019-04-11 09:45:31 +08:00
我是用户有一个 version 字段,jwt 里面存 username 和 version,把 username 和 version 存到 redis,每次登陆 version 加 1,然后清除 redis 缓存,上一个 token 来了判断 token 里面的 version 字段,不相等就返回 401
alexmy
2019-04-11 11:29:53 +08:00
把 JWT 搞复杂了,就相当于自己实现了一遍 session。
zy445566
2019-04-11 11:53:51 +08:00
简单 jwt 里面记录用户 id 和生成一个随机值,登陆的时候用户表存一下这个随机值。验证用户的时候拿用户 id 去查用户表看看这个随机值是不是就是 jwt 的随机值,如果不是,就作废当前 jwt 就好了
jerray
2019-04-11 13:28:05 +08:00
用 JWT 的话也是能做的,需要实现一套黑名单机制。首先对每个 JWT 生成唯一 ID,用 jti 放在 payload 里面。当你要给某个 Token 设置为无效时,就把这个 ID 放到黑名单里。因为你的 Token 是有过期时间的,所以仅需要对未过期的 Token 进行黑名单检查。

缺点是需要额外的存储和查询。需要存储用户生成的每个 Token ID。因为有过期机制存在,可以定时对过期的 Token ID 记录进行清理来节省空间。
reus
2019-04-11 13:49:53 +08:00
“只能同时在一个设备(端)登录”这种需求定期抽样检查就行了,那么严格干嘛,浪费资源。
jswh
2019-04-11 15:13:56 +08:00
当你涉及到需要服务端存储登录态的时候,其实就是 session 了。JWT 这种就是在客户端存储的登录态,只不过做了协议约束和加密。
Alife8
2019-06-04 11:04:01 +08:00
我在寻找一种允许最多 x 个设备登录的最优方案.至于 1 个设备(帐号),似乎要好解决一些。想法和上面几位同学有相似!
1.在用户表多加一个字段 R
2.给 JWT 设定刷新时间
3.给 JWT 数据上加入 R 字段
当用户新登录时,给 R 一个随机值,并加入到 JWT 中返回给用户。
JWT 要刷新时,判断 JWT.R 值和用户表.R 值是否相等,不同则要求用户重登录,相同则返回新的 JWT。
当然这个 JWT 只有在刷新时才判断,若要解决这个问题可以加入一个黑名单缓存表,在用户新登录时根据最后登录时间判断上次生成的 JWT 刷新时间是否还未到。这样在用户请求数据时先查一下黑名单。这样还有一个好处,在用户修改了密码后之前的 JWT 就无效了.

不足:不够优雅
优点:似乎也只能这样了
Alife8
2019-06-04 11:12:11 +08:00
刚说的多加一个 R 其实也没必要,直接用最后登录时间代替就好!
PS:v2 上居然不能编辑!!
0x1001
2020-09-24 09:44:11 +08:00
konglizhi3362
2021-01-26 11:35:39 +08:00
登录的三种模型:
多地登录:同一账号可以在任意地点同时登录,互不影响
单地登录:在同一时间一个账号只能在一个地点登录,新登录会挤掉旧登录者
同端互斥登录:在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线
楼主需要的是第二种,单地登录,建议了解一下 sa-token 框架,这个框架有登录问题解决方案,一行代码解决你的问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/553765

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX