大佬们好, JWT 如何防止多端登录 ? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
junwind
V2EX    程序员

大佬们好, JWT 如何防止多端登录 ?

  •  
  •   junwind 2024-03-15 15:09:02 +08:00 10012 次点击
    这是一个创建于 575 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,现在登录,我使用了 JWT 机制,但是怎么防止一个用户,在多个设备上登录呢?

    55 条回复    2024-03-20 09:41:44 +08:00
    angel001ma
        1
    angel001ma  
       2024-03-15 15:11:34 +08:00
    搜索单点登陆
    OutOfMemoryError
        2
    OutOfMemoryError  
       2024-03-15 15:12:29 +08:00   4
    @angel001ma #1 单点登录指的是在单个站点登录后同步其他站点的登录状态,不是防多端登录用的吧
    996635
        3
    996635  
       2024-03-15 15:14:48 +08:00
    防止多端登录和 JWT 没关系, 后端维护 token 的生效状态即可
    liuhan907
        4
    liuhan907  
       2024-03-15 15:15:01 +08:00
    jwt 就是为了给你多端登陆用的,你现在要防止。
    yrzs
        5
    yrzs  
       2024-03-15 15:15:13 +08:00
    将 jwt 存入 redis,判断 token 是否是 redis 里的
    Akitora
        6
    Akitora  
       2024-03-15 15:15:16 +08:00
    感觉 JWT 就主打一个无状态,在服务端和客户端都再额外维护一个状态绑定设备有点怪怪的
    Helios0
        7
    Helios0  
       2024-03-15 15:16:31 +08:00
    JWT不支持,本身就是面向离线的设计,你说的这个场景是 session 。
    NessajCN
        8
    NessajCN  
       2024-03-15 15:16:38 +08:00
    jwt 只是个验证工具,对于用户的登录端的限制需要你自己写 session control
    因为很显然,你要防止用户多端登录,首先需要服务端知道用户已经登录
    fengzhongdeyihan
        9
    fengzhongdeyihan  
       2024-03-15 15:18:50 +08:00
    返回 jwt token 之前绑定 uid 和 token 到 redis 中.
    然后校验的时候拿 jwt 的里面的 token 和 redis 里面的 token 对比.
    tonywangcn
        10
    tonywangcn  
       2024-03-15 15:19:17 +08:00
    签发 jwt 时,把 session id 放到 token 中
    0o0O0o0O0o
        11
    0o0O0o0O0o  
       2024-03-15 15:19:45 +08:00 via iPhone   8
    有状态与 JWT 在本站能不能算排名前十的技术争论主题?
    fkdog
        12
    fkdog  
       2024-03-15 15:19:56 +08:00
    jwt 关联设备 id ,设备 id 可以直接存在 jwt 里或者服务端存储,检测到请求对应的设备 id 与签发 jwt 的设备不一致则直接拒绝访问。
    shakaraka
        13
    shakaraka  
    PRO
       2024-03-15 15:20:05 +08:00   1
    你这是有状态的需求。明显是不符合 JWT 的使用逻辑强上。
    thinkershare
        14
    thinkershare  
       2024-03-15 15:21:28 +08:00
    JWT 不支持你这个功能,你不应该使用 JWT 维护用户的 SESSION.
    javalaw2010
        15
    javalaw2010  
       2024-03-15 15:22:24 +08:00
    防止不了,jwt 本身是无状态的协议,你要防止多端登录,就必须记录 token ,此时 jwt 就退化为 session 了,所以我一直觉得目前的风气有点滥用 jwt ,所以我新项目中的都使用最简单的随机字符串作为 token 了,所谓返璞归真吧。。。
    cat
        16
    cat  
       2024-03-15 15:22:53 +08:00
    @0o0O0o0O0o 能,我发现很多人没懂 jwt 到底是啥意思 干嘛的,一味的想用来取代 session
    lonenol
        17
    lonenol  
       2024-03-15 15:32:54 +08:00
    你想想用传统的 cookie session 怎么防止多端登录呢?
    chendy
        18
    chendy  
       2024-03-15 15:38:42 +08:00
    @cat 按照近几年面试经验,主要是培训机构都教
    EasyProgramming
        19
    EasyProgramming  
       2024-03-15 15:40:49 +08:00
    1.使用手机号生成 jwt 字符串

    2.用户登陆后,使用手机号作为 key ,jwt 字符串作为 value ,存入 redis ,将 jwt 字符串作为 token 下发给用户

    3.用户访问时,后端解析用户传入的 jwt 字符串( token ),拿到手机号后,使用手机号去 redis 查询对应的 jwt 字符串,校验是否和一致

    以上三步,可以实现你的需求
    Biluesgakki
        20
    Biluesgakki  
       2024-03-15 15:41:02 +08:00
    确实很奇怪 不过要实现就把 token 放 redis 就行 上线的时候强行把原来有的踹了
    HarrisonLee
        21
    HarrisonLee  
       2024-03-15 15:41:12 +08:00
    既然你这样问了,那么普通 token 也适合你,为什么要使用 jwt ?
    crazyweeds
        22
    crazyweeds  
       2024-03-15 15:54:13 +08:00
    如果你要防止,那么就不能用这种无状态方案。
    当然,现实中能够见到不少用 JWT 然后又限制单个设备登录的傻缺方案,他们又维护了这个 token ,搞笑。
    如果你这个特性是硬性要求,综合用户体验,可以考虑分布式 session 共享方案,或者自己用 http header + token 实现一套,更简单有效。。
    imokkkk
        23
    imokkkk  
       2024-03-15 17:01:04 +08:00
    加一层 Redis
    joker8ren
        24
    joker8ren  
       2024-03-15 17:02:15 +08:00
    要么 session 要么放 token 做检测
    Yukineko
        25
    Yukineko  
       2024-03-15 17:09:49 +08:00
    直接换成 session
    hideon
        26
    hideon  
       2024-03-15 17:10:34 +08:00
    JWT 设计用于无状态的,单端登录回归有状态,请在服务端自行记录登录状态
    type
        27
    type  
       2024-03-15 17:13:04 +08:00
    那就没必要使用 JWT
    siweipancc
        28
    siweipancc  
       2024-03-15 20:52:41 +08:00 via iPhone
    回退到 session 设计,这是个永恒的话题哈哈哈,无解的。最大的作用也就是解决了某些人的 cookie 焦虑而已。
    rekulas
        29
    rekulas  
       2024-03-15 21:21:22 +08:00
    加个中间件就行了, 验证的时候都要过一遍,有些人直接用的服务器,有些人用的 redis 集群

    楼上一些觉得不该用 jwt 的可能过于理想化了, 因为现在很多系统都基于 jwt 概念验证而开发, 你接手后因为自身业务需求想限制登录, 没必要去把整个 jwt 换掉,这样改动工作量会比较大而且可能引来未知的 bug(因为 jwt 不仅仅代表登录有些系统可能还用来传递权限之类), 只需要入口或中间层加验证就行了, 改动是最小的, 我们之前系统就有这样的需求
    BEza5k2j7yew0VN9
        30
    BEza5k2j7yew0VN9  
       2024-03-16 01:11:33 +08:00
    在新设备登录时创新的 token ,吊销旧 token ,服务端只允许一个 token 存在
    lilei2023
        31
    lilei2023  
       2024-03-16 07:49:22 +08:00
    @angel001ma 这和单点登录有啥关系?误人子弟!
    demonzoo
        32
    demonzoo  
       2024-03-16 09:37:26 +08:00
    这种场景就别用 jwt 了吧,用 session
    me1onsoda
        33
    me1onsoda  
       2024-03-16 09:40:42 +08:00
    设计的人是个二把刀
    cndenis
        34
    cndenis  
       2024-03-16 09:58:39 +08:00   1
    用啥技术都是为了符合需求的, JWT 和 session 机制同时用也不代表就不合理. 比如说普通浏览仅验证 JWT, 在关键操作中才验证 session, 在某些场合中也是可行的嘛, 为啥非要冷嘲热讽呢
    ic3z
        35
    ic3z  
       2024-03-16 10:03:02 +08:00 via iPhone
    登录生成 token 的时候看用户有没有别的有效 token ,有的话把原先的 token 清空。 要配合 jwt 验证机制。
    R4rvZ6agNVWr56V0
        36
    R4rvZ6agNVWr56V0  
       2024-03-16 10:31:22 +08:00
    最简单的做法是使用用户状态,在用户登录时,将用户状态(如“已登录”)存储在服务器端。每次用户发起请求时,服务器都会检查用户状态。如果用户状态为“已登录”,但请求中的 Token 与服务器中的 Token 不匹配,说明用户可能在另一个设备上登录,可以拒绝该请求
    zhongjun96
        37
    zhongjun96  
       2024-03-16 10:37:31 +08:00
    @yrzs #5 这样 jwt 就没意义了,不如直接一个 uuid-token
    Azure99
        38
    Azure99  
       2024-03-16 10:57:00 +08:00
    jwt 本身就是为了无状态设计的,你要是服务端再维护一个状态,和 session 有什么区别?
    hidemyself
        39
    hidemyself  
       2024-03-16 11:15:37 +08:00
    不适合用 jwt,改造一下
    yogogo
        40
    yogogo  
       2024-03-16 11:33:46 +08:00
    你应该是维护一个用户的 token 关联登陆设备信息,每次登陆后,关联 token 跟登陆设备信息,然后请求使用的时候检查使用 token 的设备是不是跟登陆设备信息一样
    sherryqueen
        41
    sherryqueen  
       2024-03-16 11:52:53 +08:00
    jwt 本身是无状态的~. 不过你真想做, 就走了 cookie-session 那套了. 需要后端来维护 jwt 的状态了. 脱离了 jwt 本身的意义.. 一般推荐就是将 jwt 的过期时间调低~
    xylophone21
        42
    xylophone21  
       2024-03-16 12:05:00 +08:00
    你如何定义多端登录?至少在上面的讨论中看到过两种定义
    1.用第三方的客户端多端登录,别说 jwt ,即使是 session ,你也拦不住对方多端交换 sessionid/token ,然后把这些塞到 HTTP 头里。除非你每个接口都刷新,但这样万一失败一次,登录就被踢了,体验恐怕很难做好。
    2.用你的客户端,浏览器多端登录。那把客户端 Id 塞到 JWT 不就可以了
    xylophone21
        43
    xylophone21  
       2024-03-16 12:27:54 +08:00
    不好意思,写到一半想岔了,目标是防止多端登录,写着写着想成了如何实现多端登录。
    第一种情况不变,第二种情况下实际上就变成了第二个端登录时,如何吊销第一个端的 JWT ?好了标准答案来了,标准的 JWT 不支持提前吊销。那怎么办?当然是非标准的 JWT ,比如前面提到的把 JWT 存到 Redis ,以及如果你更多的搜一下可以找到的优化方案--只存吊销列表的布隆等
    ns09005264
        44
    ns09005264  
       2024-03-16 12:40:40 +08:00
    我觉得,jwt 最大的意义是自带信息。

    生成 jwt token 的时候除了必要的用户信息外,还可以加上登录时的设备信息,比如 ip 、user-agent 或其他识别信息等。这样 jwt token 里就包含设备信息了。
    后续验证 jwt token 时,看它的请求头里和 jwt token 包含的信息是否对应得上,对不上就是多端使用 jwt token 了

    比如该用户在 PC 浏览器上登录了,服务器为此生成了 jwt token ,这个 token 中包含的 user-agent 是 pc 的。
    后面该用户把 jwt token 复制到 Android 浏览器上用来使用,但是请求头中的 user-agent 和 jwt token 里的对应不上,那么就是异端登录了。
    yannxia
        45
    yannxia  
       2024-03-16 12:43:23 +08:00
    原来怎么做,现在就怎么做,Session 分了一个 ID ,JWT 你也可以。没什么区别
    ns09005264
        46
    ns09005264  
       2024-03-16 12:56:51 +08:00
    https://gateway.pinata.cloud/ipfs/QmWv2NmD5iLVTsSo3QkEsGnHKxtQqMoeZZTs76ohGz1aHC

    图里这个 jwt token 是在 linux 下 firefox 中登录时生成的,如果用户把这个 token 拿到 windows 上的 chrome 去用,只需要获取请求头中的 user-agent 就可以判断它是异端登录。整个过程依旧是无状态的,根本不需要在服务器的什么地方维护用户的登录和设备信息。
    Glkcv
        47
    Glkcv  
       2024-03-16 13:34:08 +08:00
    建议别用 jwt
    FYFX
        48
    FYFX  
       2024-03-16 13:36:11 +08:00
    @ns09005264 #46
    依赖 ua 就不太靠谱吧
    hafuhafu
        49
    hafuhafu  
       2024-03-16 13:47:59 +08:00
    还是要在服务端维护状态进行判断。JWT 本身是无状态的,并不代表它一定要用在完全无状态的场景,可以当成本身就是一个编码过的字符串,里面有信息而已,完全可以继续用。
    akagishigeru
        50
    akagishigeru  
       2024-03-16 13:52:01 +08:00
    @angel001ma 兄弟别误人子弟,这叫单端登录,单点其实是全端登录
    ns09005264
        51
    ns09005264  
       2024-03-16 14:00:55 +08:00
    @FYFX 只是用 user-agnet 举个例子,不想那么严格的时候可以根据 user-agent 来判断,只要别在验证不通过时明确告知原因就能阻挡一部分非法请求。想严格一点可以用浏览器指纹或设备 id 之类的。总之这是多设备识别的时间,有状态的 sessionID 能做到的,无状态的 jwt token 也能做到。
    skull
        52
    skull  
       2024-03-16 18:02:59 +08:00 via iPhone
    @angel001ma 原来你是这么字面理解的啊
    Plutooo
        53
    Plutooo  
       2024-03-17 00:57:36 +08:00
    看到 11 楼笑出声
    Zy143L
        54
    Zy143L  
       2024-03-18 00:39:26 +08:00
    是想设计成挤号还是禁止多登陆呢
    挤号的话就存 JWT 判断提交的是否和库里面的一样就行了
    yrzs
        55
    yrzs  
       2024-03-20 09:41:44 +08:00
    @zhongjun96 确实没意义 但是强行改 jwt 这样最方便
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2529 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 04:35 PVG 12:35 LAX 21:35 JFK 00:35
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86