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

关于前后端分离中的 Session 和 Token ,请教大家几个问题。

  •  
  •   mitu9527 · 2020-09-01 22:09:39 +08:00 · 4579 次点击
    这是一个创建于 1548 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1.对于会话来说,JWT 真的算 Token 么?虽然名字中带 Token,但是对于会话来说,我觉得 JWT 其实更像是一种“客户端会话”。客户端会话虽然有一些吸引力,但是带来的问题好像比服务端会话更多,怎么还有好多人推荐使用,是我学艺不精,还是他们没搞清楚?

    2.服务端会话已经很成熟易用了,在前端也只需要保存一个会话 ID 而已,在传统的开发模式中这个会话 ID 基本上都是保存在 Cookie 中的。如果在前后端分离这种开发模式下,真的用不了 Cookie (比如说部分客户端不支持 Cookie 或者跨域了),那直接基于 HTTP 头部实现一种替代的会话 ID 传输方式,然后再找一个地方存储这个会话 ID,不就可以了么?我看好像也有些人这么做并且管这个叫 Token 。

    3.我还见到一些人说“先输入用户名和密码进行登陆,成功后返回一个 Token,然后后续请求都带上这个 Token,定期更换即可”。从功能上讲,这种 Token 感觉十分类似我们做“保持登陆 7 天”时的那种自动登陆 Token,是么?那这种 Token 和会话好像已经没关系了啊!

    所以说在前后端分离中不使用 Cookie 的情况下,Session 和 Token 到底该怎么用?

    第 1 条附言  ·  2020-09-02 10:55:30 +08:00
    关于前后端分离中常说的 Token 和 Session,我已经研究了一天了,看了得有几十篇文章了。说说我目前的看法吧。

    Token 本质上其实就是“客户端会话”,而 Session 则是经典的“服务端会话”。JWT 就是一种设计良好的、得到广泛支持的 Token (如果我决定用 Token 而不是用 Session,那我大概率也会直接用 JWT,不会自己去设计一套 Token )。

    虽然很多文章中列出了 Token 的优点,比如安全性啊、跨域啊、所有客户端都可以支持,等等一大堆,其实好多都是和 Cookie 相关的,不应该拿出来说事儿,剩下的也不怎么经得起仔细琢磨。最后,我认为 Token 最大的优点就是其“客户端会话”本质中的“客户端”三个字,也就是好多人说的“去中心化”和“无状态”。而 Token 最大的缺点是:服务端主动销毁一个 Token 时,如果不在服务端记录,比如通过 Redis,那么保存在客户端的 Token 仍然会保持有效。虽然为 Token 所使用的 Redis 在量级上不如为 Session 所使用的 Redis 大,但这样做多少还是有些违背了“去中心化”的初衷。这个缺点从本质上来讲,还是因为其“客户端”引起的。所以说 Token 成也客户端,败也客户端。

    所以说 Token 和 Session 的比较实际上是“客户端会话”和“服务端会话”的比较。我看好多人在字里行间都透露着 Token 比 Session 更“优秀”,是替代 Session 的;但是在我看来 Token 只不过比 Session 更“新”罢了,它和 Session 不是纯粹的替代关系,应该根据实际情况决定使用哪一个,甚至说结合二者。

    这就是我目前对 Token 和 Session 的认知,欢迎大家指正。
    28 条回复    2020-09-02 12:39:05 +08:00
    Ptu2sha
        1
    Ptu2sha  
       2020-09-01 22:23:05 +08:00   ❤️ 1
    多个业务的情况下 Session 是单个业务维护登陆用户信息的
    而 token 是多个系统共用的登陆鉴权的
    KuroNekoFan
        2
    KuroNekoFan  
       2020-09-01 22:41:23 +08:00 via iPhone   ❤️ 2
    jwt 是去中心化,自包含的,必须理解这两点
    Mithril
        3
    Mithril  
       2020-09-01 22:47:57 +08:00   ❤️ 1
    这个东西主要是分布式或者负载均衡里面用,当你同一个用户的两个请求打到不同服务实例上的时候,这两个实例都需要有能力验证它的合法性。
    session 的话你就得保证两个请求都进到同一个服务器里才行。或者你确定你的业务规模用不着做这些东西,那直接用 session 最方便。
    wellsc
        4
    wellsc  
       2020-09-01 22:49:30 +08:00 via iPhone
    @Mithril 分布式 session 了解一下
    mitu9527
        5
    mitu9527  
    OP
       2020-09-01 22:51:38 +08:00
    @KuroNekoFan 但是我感觉 JWT 的缺点也挺多的,觉得至少在会话这块用起来不合适。
    mitu9527
        6
    mitu9527  
    OP
       2020-09-01 22:53:48 +08:00
    @Mithril 服务端会话有很多种成熟的方案了,小型、中型和大型架构都有,这个觉得不是问题。
    tinycold
        7
    tinycold  
       2020-09-01 22:55:18 +08:00 via Android   ❤️ 1
    其实你说的那些都不是啥问题,JWT 最大的问题是一旦发出去了,在它的失效时间到来之前你永远无法撤销它的认证,要是存 redis 里过滤那就太好笑了。

    它最大的好处就是"无状态",正如楼上说的,如果要考虑到复杂的认证 /鉴权系统,JWT 是很有优势的,因为 JWT 的灵活性远远高于 session 。如果只是简单的客户端认证,其实和前后端是否分离关系不大,就直接用自带的 session 认证系统基本就能 hold 住。否则你还得设计 token 分发,刷新,过期处理等等麻烦的事情。

    不过,小孩子才做选择,成年人什么都要。你可以用 jwt 来存你的 session id,这样不就完美解决这个问题了!!!(狗头,狗头)
    KuroNekoFan
        8
    KuroNekoFan  
       2020-09-01 22:57:01 +08:00 via iPhone
    @mitu9527 时代变了,以前可能凭证( credentials )和 会话( session )混在了一起,但现在,可能不这样做了(当然你还是可以这样做),而 jwt 的好处在于,payload 是自定义格式的数据
    mitu9527
        9
    mitu9527  
    OP
       2020-09-01 23:01:42 +08:00
    @tinycold 嗯,JWT 最大的特点是存在客户端,而不是服务器端,所以“无状态”,但也正式因为没有存在服务端,所以服务端没办法主动让其失效,只能等其过期。
    timothyqiu
        10
    timothyqiu  
       2020-09-01 23:02:43 +08:00   ❤️ 2
    Token 这个词本身不应该狭隘地理解为某个特定领域 /框架中的含义,计算机科学范畴广泛使用 Token 这个术语,本质上只要是「一段对用户含义不透明的数据」都可以叫 Token 。JWT 既然是 JSON Web Token,那它就是 Token 。

    「服务端会话还是客户端会话」与「使用 Cookie 还是 Token 」是正交的,Cookie 和 Token 只是信息的载体,信息是 SessionID 还是完整的 Session 数据其实无所谓。JWT 的优势是有签名,可以防止数据被篡改。

    前后端分离一般见到的都是用 Authorization 报头传 JWT 。RESTful API 的话客户端会话比较多,因为好实现、方便 HTTP 缓存、方便 Scale 。
    mitu9527
        11
    mitu9527  
    OP
       2020-09-01 23:14:14 +08:00
    @timothyqiu 有点懵了,不过还是要说声感谢!
    j2gg0s
        12
    j2gg0s  
       2020-09-01 23:20:20 +08:00   ❤️ 1
    在你的描述中,session 是指 cookie 中的 kv,token 是指要 header 里面的 kv,那么 session 的相对优势是不需要请求时手动处理,劣势在于 cookie 使用时不易 cross-domain 和 samesite 之类的限制。

    JWT 的优势在于可以存储一些无害的信息,减少调用,同时可以通过校验来避免恶意的 DDOS 击穿系统。绝大部分的操作我理解还是不会直接相信 JWT 中的数据。
    xuanbg
        13
    xuanbg  
       2020-09-02 07:26:20 +08:00   ❤️ 1
    @tinycold 复杂的认证 /鉴权系统 JWT 根本做不了。把复杂的授权信息放 payload 就是个笑话,而且,最要命的是做不到授权信息的动态更新。


    @mitu9527 JWT 最大的特点也是它的最大缺点。
    Mithril
        14
    Mithril  
       2020-09-02 07:39:08 +08:00
    @wellsc 去中心化了解一下
    Mithril
        15
    Mithril  
       2020-09-02 07:52:00 +08:00
    @mitu9527 这个就是问题,你可以了解一下这些成熟的服务端会话和 JWT 有什么区别。
    本质上 JWT 只是解决了“Server 必须要存储 session 信息”这么个事。
    因为 Server 端需要存储 session 信息,所以分布式或者复杂均衡情况下需要通过 session 共享,或者数据库,nginx 配置等等方法要么在多个实例里共享 session,要么保证同一个用户的每次请求都打到一个实例里。
    而 JWT 你可以根据需求做到不需要先验知识的验证,从而保证多个实例在验证的时候不需要共享先验知识。Token 这种东西也足够灵活,如果简单的验证不够的话你也可以往里面存个 session id 。
    Mutoo
        16
    Mutoo  
       2020-09-02 08:04:30 +08:00
    JWT 有很多额外的好处。例如可以用非对称加密鉴权,这种无状态鉴权除了 scaling 的好外以外,还有其它玩法:只要把 public key (注意不是 private key )交给乙方,乙方就可以快速鉴权甲方用户,并且也是无状态的,无无需额外的请求。
    renmu123
        17
    renmu123  
       2020-09-02 08:32:17 +08:00 via Android
    session 是个概念,而 token 是一个具体实现,cookie 也是
    meshell
        18
    meshell  
       2020-09-02 09:10:11 +08:00   ❤️ 1
    token 无法主动删除更新用户的凭证.
    dany813
        19
    dany813  
       2020-09-02 09:23:19 +08:00
    老哥们一般是怎么刷新 token 的,定时刷新吗
    wellsc
        20
    wellsc  
       2020-09-02 10:01:46 +08:00
    @Mithril jwt token 无法被服务端主动撤销,以及潜在的安全问题,就注定无法替代 session ,个人感觉 jwt 存储 session id,服务端使用分布式 session 才是比较好的解决方案
    mitu9527
        21
    mitu9527  
    OP
       2020-09-02 10:57:44 +08:00
    @dany813 一般都会设置一个过期时间,这个过期时间也保存在客户端,并随每次请求发送给服务端,服务端做验证,判断其是否过期,过期后就告知客户端该 Token 无效,让客户端重新发起登陆请求去重新生成新的 Token 就可以了。
    also24
        22
    also24  
       2020-09-02 10:59:09 +08:00   ❤️ 1
    悄悄的丢链接:
    https://www.v2ex.com/t/656457

    JWT 是一种 token 生成方式。
    Session 是代指一整个会话过程的虚拟概念。

    二者并不在同一个层级。
    mitu9527
        23
    mitu9527  
    OP
       2020-09-02 11:04:14 +08:00
    @also24 这篇文章我看到了。
    siganushka
        24
    siganushka  
       2020-09-02 11:46:05 +08:00   ❤️ 1
    “会话”只是一个抽象概念,不管是传统的服务端 session,还是 API 里的 JWT,本质都是把两次本不相干的链接关联起来,session 里的 session_id 和 jwt 中的 token 都需要服务端管理和维护,由客户端负责存储,两次链接发送的值一样,即可认为是同一个会话。

    像 JWT 一样,服务端的 session 也可以自定义 session_id 和存储逻辑,因此本质上我认为他们是同一个抽象对于不同场景的不同实现,其直接有细微差别,比方说如果你把 session_id 在 cookie 中的 key 改成 token,值为 JWT 的 token 值行不行?然后自己实现存储逻辑,这不和传统的服务端 session 一样么?

    之所以你觉得不一样,可能是因为他们的场景有细微的差别,1 是浏览器对于 cookie 的支持相对于 APP (或各种客户端)更好,因此默认不需要客户端手动操作,服务端就能实现整个 session 实现。2 是对于 JWT 的定义中,一旦服务端颁发 token 给客户端,在过期之前服务端无法撤销。

    如果让你自己实现一个类似服务端的 session 功能,你想想你该怎么做?想到最后可能就是另一个 JWT !
    timothyqiu
        25
    timothyqiu  
       2020-09-02 11:52:03 +08:00
    按照附言里的定义,大概比较一下:

    1. 客户端可以直接修改 Session 里的会话 ID 来冒充其它人;但客户端没法修改 JWT 里的数据,因为它是签了名的。

    2. 客户端可以直接修改 Session 的 Cookie 过期时间(甚至不理会),所以服务器必须自行维护会话过期时间;但客户端没法修改 JWT 里的过期时间,因为它是签了名的,所以服务器不用维护会话过期时间。

    3. 服务器可以很方便地主动结束 Session,无需额外设施; Token 如果需要服务器主动回收,则必须自行维护黑名单。

    不过对于 Token 在第 3 点 Token 所引入的额外设施,Session 是在第 2 点里引入的,而且 Token 只需追踪服务器主动结束的黑名单,Session 必须则必须为所有已登录用户存一份。

    但话还是得说回来,不要重新定义概念,按照正常的定义会更好地理解你想研究的问题。Session 就是会话,你称作 Session 的东西是「基于 Cookie 的服务器会话」,你称作 Token 的东西是「基于 Token 的客户端会话」。Cookie 也可以客户端会话,Token 也可以服务器会话。Cookie 和 Token 是一类东西,Session 是另一类东西。
    timothyqiu
        26
    timothyqiu  
       2020-09-02 12:00:20 +08:00
    啊,第一点里如果你的框架签名或者加密了会话 ID,就和 JWT 没啥区别了 🤷‍♂️
    mitu9527
        27
    mitu9527  
    OP
       2020-09-02 12:09:54 +08:00
    @timothyqiu
    1.我拿到了 JWT,还改它干啥,直接盗用了;这和会话 ID 被盗取是一样的。再者会话 ID 就算被改了,服务端也不会认。只要会话 ID 生成的方法没问题,想碰撞会话 ID 也是非常难的。
    2.那个是 Cookie 的问题吧。再说在服务端会话数据里面加一个过期时间,和在 JWT 中加一个过期时间有什么本质区别么?能在 JWT 中加,那也能在服务端会话中加。
    3. 这个是一个本质的区别。

    在前后端分离这块,很多人所说的 Token 确实就是客户端会话,那些 Token 的优缺点也都是客户端会话的优缺点。不过在超出这个范畴,那 Token 的含义就不局限于“会话”了。
    timothyqiu
        28
    timothyqiu  
       2020-09-02 12:39:05 +08:00
    @mitu9527 对,所以本质上是想要比较客户端会话和服务器会话。

    Token 和 Cookie 都只是数据的载体,优缺点没什么大区别。无论是加密 /签名 Cookie 数据,还是往 Cookie 里额外存过期时间,本质上就像楼上那个哥们说的,完善到最后你会发现往 Cookie 里存的就是另一种形式的 JWT 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3766 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 04:20 · PVG 12:20 · LAX 20:20 · JFK 23:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.