初次尝试 JWT,发现一个账号生成多个 JWT token 后,只要在这些 token 还没过期前都是有效的
例如账号 A 在 15:30 分登录生成了 token0,有效时间为 1 小时,过了 5 分钟账号 A 再次登录生成了 token1 有效时间还是为 1 小时。 这时候 token0 和 token1 都是合法的? 我之前以为 token1 会把 token0 给刷新掉……
那么如何实现一个账号只能同时在一个设备(端)登录呢?想到了如下几种方式:
各位大佬有什么好方法吗?
1
noe132 2019-04-10 16:13:55 +08:00 1
直接用 session。
|
2
whileFalse 2019-04-10 16:14:44 +08:00 2
你需要 session。jwt 面向离线认证设计,其本就不准备支持吊销功能。
session 放内存或者缓存服务,不会对数据库造成压力。 |
3
aimerforreimu 2019-04-10 16:19:22 +08:00 via Android 1
jwt 设计的时候就有专门的使用场景的,你这样需求的话,用 session 比较合适,物尽其用是最吼的,没有必要强制用 jwt 的
|
4
hantsy 2019-04-10 19:33:04 +08:00 2
如果用 Spring, 可以使用 Spring Session ( 可以选择由 Redis 等存储), 除了实现传统 HTTP Session 接口外,,还是可以在应用之间共享,可以作为 API 安全方案,也适合于 microservice 架构.
https://github.com/hantsy/spring-microservice-sample#secures-microservice 如果自己实现,不管是什么语言,也可以尝试将 Token 写入 Redis,Redis 写入时可以可以设置 Timeout。 |
5
xuanbg 2019-04-10 20:18:20 +08:00
JWT 不支持的,自己撸一个吧。我的经验是把一些用户信息搞成一个对象放 Redis,生成的 Token 只包含令牌本身的 ID、用户 ID 和验证串就行了。这样服务端在验证 Token 的时候就很灵活了,可以轻松实现楼主的单设备登录需求。
|
6
freakxx 2019-04-10 23:56:23 +08:00
如果是 drf 那套的话,
login 的时候直接把 token 更新下就可以。 jwt 的过期和刷新的理念,当时用的时候觉得不太顺手,git 上面好像还有一个 issue 就是讨论这个问题。 |
7
kangzai50136 2019-04-11 05:15:12 +08:00 via Android
直接 spring session 吧,虽然我自己用 jwt+redis。我当初听说分布式的话 jwt+redis 比 session 好才选了 jwt。
|
8
whileFalse 2019-04-11 08:30:16 +08:00
@freakxx 过期和刷新概念的目的就是弥补 jwt 不支持服务端主动吊销的问题。
如果业务不需要主动吊销,直接签发无限时间或 99 年的 jwt 即可。 |
9
huangdayu 2019-04-11 09:28:02 +08:00
存 jwt 的 id,对 id 进行操作,删除则是吊销
|
10
zhenjiachen 2019-04-11 09:45:31 +08:00
我是用户有一个 version 字段,jwt 里面存 username 和 version,把 username 和 version 存到 redis,每次登陆 version 加 1,然后清除 redis 缓存,上一个 token 来了判断 token 里面的 version 字段,不相等就返回 401
|
11
alexmy 2019-04-11 11:29:53 +08:00
把 JWT 搞复杂了,就相当于自己实现了一遍 session。
|
12
zy445566 2019-04-11 11:53:51 +08:00
简单 jwt 里面记录用户 id 和生成一个随机值,登陆的时候用户表存一下这个随机值。验证用户的时候拿用户 id 去查用户表看看这个随机值是不是就是 jwt 的随机值,如果不是,就作废当前 jwt 就好了
|
13
jerray 2019-04-11 13:28:05 +08:00
用 JWT 的话也是能做的,需要实现一套黑名单机制。首先对每个 JWT 生成唯一 ID,用 jti 放在 payload 里面。当你要给某个 Token 设置为无效时,就把这个 ID 放到黑名单里。因为你的 Token 是有过期时间的,所以仅需要对未过期的 Token 进行黑名单检查。
缺点是需要额外的存储和查询。需要存储用户生成的每个 Token ID。因为有过期机制存在,可以定时对过期的 Token ID 记录进行清理来节省空间。 |
14
reus 2019-04-11 13:49:53 +08:00
“只能同时在一个设备(端)登录”这种需求定期抽样检查就行了,那么严格干嘛,浪费资源。
|
15
jswh 2019-04-11 15:13:56 +08:00
当你涉及到需要服务端存储登录态的时候,其实就是 session 了。JWT 这种就是在客户端存储的登录态,只不过做了协议约束和加密。
|
16
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 就无效了. 不足:不够优雅 优点:似乎也只能这样了 |
17
Alife8 2019-06-04 11:12:11 +08:00
刚说的多加一个 R 其实也没必要,直接用最后登录时间代替就好!
PS:v2 上居然不能编辑!! |
18
0x1001 2020-09-24 09:44:11 +08:00
@zhenjiachen 可
|
19
konglizhi3362 2021-01-26 11:35:39 +08:00
登录的三种模型:
多地登录:同一账号可以在任意地点同时登录,互不影响 单地登录:在同一时间一个账号只能在一个地点登录,新登录会挤掉旧登录者 同端互斥登录:在同一类型设备上只允许单地点登录,在不同类型设备上允许同时在线 楼主需要的是第二种,单地登录,建议了解一下 sa-token 框架,这个框架有登录问题解决方案,一行代码解决你的问题 |