V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
junwind
V2EX  ›  程序员

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

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

    如题,现在登录,我使用了 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 的设备不一致则直接拒绝访问。
    wunonglin
        13
    wunonglin  
       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 就可以判断它是异端登录。整个过程依旧是无状态的,根本不需要在服务器的什么地方维护用户的登录和设备信息。
    Lexgni
        47
    Lexgni  
       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 本身是无状态的,并不代表它一定要用在完全无状态的场景,可以当成本身就是一个编码过的字符串,里面有信息而已,完全可以继续用。
    JaguarJack
        50
    JaguarJack  
       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   ·   实用小工具   ·   1035 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:05 · PVG 03:05 · LAX 12:05 · JFK 15:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.