V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
junwind
V2EX  ›  程序员

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

  •  
  •   junwind · 263 天前 · 8011 次点击
    这是一个创建于 263 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

    图里这个 jwt token 是在 linux 下 firefox 中登录时生成的,如果用户把这个 token 拿到 windows 上的 chrome 去用,只需要获取请求头中的 user-agent 就可以判断它是异端登录。整个过程依旧是无状态的,根本不需要在服务器的什么地方维护用户的登录和设备信息。
    Lexgni
        47
    Lexgni  
       262 天前
    建议别用 jwt
    FYFX
        48
    FYFX  
       262 天前
    @ns09005264 #46
    依赖 ua 就不太靠谱吧
    hafuhafu
        49
    hafuhafu  
       262 天前
    还是要在服务端维护状态进行判断。JWT 本身是无状态的,并不代表它一定要用在完全无状态的场景,可以当成本身就是一个编码过的字符串,里面有信息而已,完全可以继续用。
    JaguarJack
        50
    JaguarJack  
       262 天前
    @angel001ma 😂兄弟别误人子弟,这叫单端登录,单点其实是全端登录
    ns09005264
        51
    ns09005264  
       262 天前
    @FYFX 只是用 user-agnet 举个例子,不想那么严格的时候可以根据 user-agent 来判断,只要别在验证不通过时明确告知原因就能阻挡一部分非法请求。想严格一点可以用浏览器指纹或设备 id 之类的。总之这是多设备识别的时间,有状态的 sessionID 能做到的,无状态的 jwt token 也能做到。
    skull
        52
    skull  
       262 天前 via iPhone
    @angel001ma 原来你是这么字面理解的啊
    Plutooo
        53
    Plutooo  
       262 天前
    看到 11 楼笑出声
    Zy143L
        54
    Zy143L  
       261 天前
    是想设计成挤号还是禁止多登陆呢
    挤号的话就存 JWT 判断提交的是否和库里面的一样就行了
    yrzs
        55
    yrzs  
       258 天前
    @zhongjun96 确实没意义 但是强行改 jwt 这样最方便
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1303 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 17:59 · PVG 01:59 · LAX 09:59 · JFK 12:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.