V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
aboat365
V2EX  ›  信息安全

为什么那么多 web 系统使用 jwt token 来做身份认证

  •  
  •   aboat365 · 2021-04-29 15:56:52 +08:00 · 12438 次点击
    这是一个创建于 1333 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我个人觉得大量的 web 系统在滥用 jwt token 技术。jwt token 签发后可使用私钥来验证其是否过期和篡改,这个技术用来做下载链接、邮箱验证、或短时间内的一次性验证业务是非常好的。但如果用来做 web 系统的身份认证,那简直糟糕透顶。在真正无状态下,很难平衡签发时间和安全之间的矛盾,还有无法续期导致的用户体验问题。当然,可以打补丁,甚至变得有状态,最后解决以上问题。但是,为什么一开始不用 cookie + session 呢?想听听大家的看法。

    第 1 条附言  ·  2021-04-29 19:09:05 +08:00

    #附言 为了更好讨论本主题,下面附加两种会话身份认证的流程,其中前端不限于网页浏览器。

    HTTP 协议使用 JWT 无状态会话身份认证一般流程

    • 前端输入账户密码登录;
    • 服务端验证账户密码通过后,使用私钥签发一个字符串类型的 token ,此 token 一般包含类似账户 ID 等唯一身份凭证和过期时间等信息。将此 token 返回给前端;
    • 前端将收到的 token 存储起来,在后续每次请求中带上此 token ;
    • 服务端收到前端请求,从中取出 token,用公钥验证 token 是否篡改和过期,检验通过后解析出 token 中的身份凭证即可。

    HTTP 协议使用 cookie + session 有状态会话身份认证一般流程

    • 前端发起第一次请求;
    • 服务端收到前端请求,发现请求头 Cookie 字段不存在(未携带值),将生成一个字符串类型的 session id,并返回给前端(在头中字段 Set-Cookie);
    • 前端收到回应后,将回应头中的 Set-Cookie 字段值存储起来,网页浏览器将自动存于 cookie 中,后续每次请求将带上此值( session id )。如果后续任何回应头中带了 Set-Cookie,那么将重复执行本步骤。
    • 前端输入账户密码登录;
    • 服务端验证账户密码通过后,将此账户信息与前步骤生成的 session id 绑定(绑定信息存于服务端,此处称为session上下文,并设置过期时间,过期移除)。为了安全起见,当然也可重新生成 session id ,并将此新 session id 返回给前端;
    • 前端后续每次请求中带上存储于本地的 session id;
    • 服务器收到请求,获取头中 Cookie 字段值(session id),在 session 上下文中查找,找到后将过期时间刷新,未找到重新登录。
    第 2 条附言  ·  2021-05-06 00:58:23 +08:00

    首先感谢@also24《有关 Session 的那些事儿》,文中详细介绍了 Web 会话中的名词和概念,特别是介绍了 Server Side Session 和 Client Side Session 两种模式,

    为了探寻究竟,我查询了一下 v2ex 中关于 jwt 的主题贴,发现不少贴子(好资料尽在眼前)。其中最早的帖子甚至可追溯至2014年。遥想当年,大街小巷,大爷大妈都开始用上智能手机了,更别提年轻的小伙子姑娘们,个个手抖的跟筛子似的玩微信摇一摇。那时 3G 网络已全面覆盖,4G 网络建设如火如荼,正是移动互联网风起云涌的时代,移动APP也是趁东风,夜放花千树。正是在这样的背景下,大量年轻程序员加入移动 APP 的开发。其中有位程序员发出以下疑问:

    为什么 APP 要用 token 而不用 session 认证?

    移动 APP 的使用场景登录一次,此后这 APP 打开应该就是已登录。在这种使用场景下,如果会话使用 cookie + session 方案(Server Side Session),最简单的方法就是把 session id 的有效期延长。但简单的把会话有效期延长是不安全的,为了解决这个问题,可以加入 remember me id 实现长期记住登录状态。在短期的 session id 过期后,使用长期 remember me id 重新自动登录。在该主题回复中,有朋友提到,APP 一关闭,储存在 cookie 管理器中的数据自动清空了(待考证)。即使这个问题存在,我估计也是好处理的,只需把 session id 存在别处不清空的地方即可。

    如上文中所述,移动APP会话使用cookie + session 方案也是能满足需求的。但是为什么 APP 要用 token 而不用 session 认证?窃以为是以下原因:

    1. 移动 APP 功能初始功能简单,快速迭代(一星期开发5个 APP,能登录就行);
    2. 移动 APP 生命周期短(天知道这 APP 能活几天);
    3. 早期移动 APP 开发者知识面较窄(大量招人,培训四个月上岗,工资八千起步);
    4. 适配移动 APP 使用场景的 cookie + session 方案过于复杂;

    时间同样在2014年,vue.js 发布了(同年,HTML5完成标准制定),在此之前,AngularJS 和 React 也已诞生,前端领域开启三足鼎力时代。三年后,有人又问了一个问题:

    请教各位一个问题, 为什么 session 机制没有被 JWT 所取代?

    从问题可看出,提问者认为 JWT 会话方案是先进的,而 cookie + session 会话方案是落后的。曾几何时,cookie + session 会话方案是 WEB 网站的标配,此时正受到 JWT 会话方案的挑战。为什么会出现这种情况,窃以为是受到移动 APP 领域大量采用 JWT 会话方案造成的。在前后端分离模式下,服务端不仅仅给移动APP提供服务,也为网页提供服务。对于这种多端服务,统一会话方案是必然的。这就造成 WEB 网站也出现了使用JWT 会话方案。但为什么会有人觉得JWT方案(Client Side Session)是先进的呢,它究竟有何优势?个人把经得起推敲的优点罗列一二:

    1. 降低服务端压力;
    2. 分布式扩展方便;

    当然,对于JWT会话方案,有人在2016年呼吁,请立刻停止使用 JWT 会话。确实,JWT会话方案并非是更为完美,替代cookie + session会话方案的新技术。如在本小标题主题的回复中,不乏有识之士指出,WEB 网站中使用 JWT会话方案存在缺点。那么,对于WEB网站使用 JWT 会话方案有什么缺点呢?如下:

    • token 无法续期
    • token 无法注销(有效期内服务端无法主动注销)

    办法总比困难多,其中对于续期问题简单粗暴的办法便是签发一个长效token,安全做法则是加一个长效 refresh token。而对于无法注销但问题,则可以在服务端加入一个黑名单功能。以上做法较为有效的解决了一些 client side session 的缺点,但有些需求仍然无法完美达到,如准确统计实时在线用户、控制账户并发登录数量等。

    97 条回复    2024-10-15 09:39:02 +08:00
    zoharSoul
        1
    zoharSoul  
       2021-04-29 16:16:31 +08:00
    因为 cookie 不好用啊, 所以要用 token,
    既然要生成 token, 与其自己想一套规则, 不如直接用 jwt 的.
    leafre
        2
    leafre  
       2021-04-29 16:42:57 +08:00
    是公钥验签防篡改,refresh_token 可以实现无缝续签,redis 黑名单控制 jwt 失效,安全和有状态之间做取舍。至于 cookie + session,无法满足多端需求
    2kCS5c0b0ITXE5k2
        3
    2kCS5c0b0ITXE5k2  
       2021-04-29 16:46:26 +08:00
    @leafre session 为什么无法满足多端需求
    wshcdr
        4
    wshcdr  
       2021-04-29 16:47:11 +08:00
    移动端又没有 session 的
    airplayxcom
        5
    airplayxcom  
       2021-04-29 16:48:39 +08:00
    那只能说明 你的项目还没有前后分离
    chendy
        6
    chendy  
       2021-04-29 16:49:44 +08:00
    公司的产品 web 端还是用 cookie 的(其实也可以说是把 token 放在了 cookie 里),没啥问题
    客户端和小程序之类的用的自定义的 token 也没用 jwt,因为有大量踢人需求 jwt 太麻烦
    wangxiaoaer
        7
    wangxiaoaer  
       2021-04-29 16:51:42 +08:00
    @wshcdr #4 移动端为什么没有 session ?
    hronro
        8
    hronro  
       2021-04-29 16:52:55 +08:00 via iPhone   ❤️ 5
    JWT token 这个说法看着好难受。JWT 里面的 T 不就是 token 的意思吗,为什么还要在 JWT 后面再加个 token ?
    wshcdr
        9
    wshcdr  
       2021-04-29 16:58:59 +08:00
    @wangxiaoaer 手机上的 app,就是没有 session 的
    est
        10
    est  
       2021-04-29 17:10:48 +08:00
    因为一群猴子发现解析 cookie 太难了。格式没有太好的 spec 。就自己用 JSON 糊了一个替代品。
    jorneyr
        11
    jorneyr  
       2021-04-29 17:10:53 +08:00
    jwt + 客户端指纹 (IP+浏览器信息...等) 就可以防止滥用的成本
    djs
        12
    djs  
       2021-04-29 17:12:36 +08:00
    @wshcdr #4 session 是放在服务端的吧
    zoharSoul
        13
    zoharSoul  
       2021-04-29 17:28:46 +08:00
    @wangxiaoaer #7
    先不说 ios, android 上的 cookie 存储你弄过吗? 多域名情况下 cookie 共享弄过吗?
    按访问速度动态更换域名的时候 cookie 怎么跟着切? 更换用户登录的时候 cookie 怎么改变?

    这时候用 token 不是更方便吗?
    wunonglin
        14
    wunonglin  
       2021-04-29 17:44:20 +08:00   ❤️ 1
    @zoharSoul #13

    后端生成 token(此 token 为自定义的随机字符串,不是 jwt),token data 存 redis 。客户端(web 、ios 、andriod 等),自行存储。请求时带上 token,此时你想带到 header,body,query param 都行呀

    这样不就满足服务端控制 token 咯?
    keppelfei
        15
    keppelfei  
       2021-04-29 17:44:24 +08:00
    存在即合理,市场决定的,移动端的兴起更需要 jwt 的出现。jwt 更多的是一种思想
    zoharSoul
        16
    zoharSoul  
       2021-04-29 17:45:34 +08:00
    @wunonglin #14 这不就是我的意思吗?
    aboat365
        17
    aboat365  
    OP
       2021-04-29 18:06:37 +08:00
    @leafre 感谢指出错误,私钥签发,公钥验证。refresh_token 、redis 黑名单确实能解决问题,但问题是需要前后端写代码去实现,而 cookie+session 方案,几乎不用写什么代码就具备这些功能。对于多端,cookie 存的只是一个 sessionID 字符串,请问支持 http 协议的端带上一个 sessionID 有啥困难,头里加 token 都没问题,带个 sessionID 就不能了?
    aboat365
        18
    aboat365  
    OP
       2021-04-29 18:12:39 +08:00
    @wunonglin 这就相当于重新打造了一套 cookie+session 方案实现。
    aboat365
        19
    aboat365  
    OP
       2021-04-29 18:20:35 +08:00
    @zoharSoul 这位兄台,其实所谓 cookie+seesion 方案,基本流程是后端生成一个 sessionID,发给前端,前端存起来,后续请求都带上这个 sessionID,实现了有状态的会话跟踪。但迫于种种安全问题,以及浏览器提供的便捷方式,如同域可带上这个 sessionID,跨域不允许; sessionID 返回后浏览器自动将其存储在 cookie 中;但是,以上是对于常规浏览器而言。既然你的是移动端 app 了,这个 sessionID 你想怎么玩就怎么玩,跟 token 使用毫无区别。
    wunonglin
        20
    wunonglin  
       2021-04-29 18:20:55 +08:00
    @aboat365 #18 不打造怎么对应不同的业务需求?
    aboat365
        21
    aboat365  
    OP
       2021-04-29 18:22:49 +08:00
    @hronro 我错了,不过懂这个意思就好。
    aboat365
        22
    aboat365  
    OP
       2021-04-29 18:27:20 +08:00
    @wunonglin 有特殊需求无法满足,自定义一套当然 ok,但问题是很多用 jwt 做身份认证的系统,真的是重新造了个轮子,还不圆。
    wunonglin
        23
    wunonglin  
       2021-04-29 18:44:50 +08:00
    @aboat365 #22 那些就是为了用而用罢了
    xuanbg
        24
    xuanbg  
       2021-04-29 19:46:28 +08:00
    @leafre 不是不能,而是麻烦。现在都是 RestAPI 的服务端,哪有 session ?搞个 token 多简单,而且也方便搞分布式。

    JWT 有他特定的优点,但滥用 JWT 真的不好。既然要有状态了,我自己生成一个 token 很难吗?几行代码的事,能贴合自己的需求,又不用额外引入第三方库。
    zoharSoul
        25
    zoharSoul  
       2021-04-29 19:48:30 +08:00
    @aboat365 #19 那既然毫无关系, 不就是 token 方案了? 无非是 token 是 jwt 还是自己造轮子, 还是 sessionid,
    那么 jwt 比起 sessionid 多携带点信息他不香吗?
    xuanbg
        26
    xuanbg  
       2021-04-29 19:51:32 +08:00
    @aboat365 这种 token 的作用确实是和 sessionId 一样的。无非就是怎么叫的问题,就不要纠结了。
    FreeEx
        27
    FreeEx  
       2021-04-29 19:55:16 +08:00
    因为有 80%的人是跟风用的,根本不了解其中利弊。
    aboat365
        28
    aboat365  
    OP
       2021-04-29 20:15:56 +08:00
    @zoharSoul 无状态 jwt 对比有状态的 cookie + session,整体代码量自然是前者少,而且看起来简单,但后者是作为标准具有广泛的实现,实际使用几乎不用写什么代码(开发者甚至不需理解其原理,现成的实现也能工作的很好)。而 jwt 即使再简单,前后端也是要写代码的,而且如果无状态 jwt 不能满足你的需求,甚至要写很多代码,所以才说很多使用 jwt 的开发者只是在重新造轮子,还造不圆。 对于 token 中可以多携带信息,这不是什么优点,虽然大家 wifi 千兆,手机都用上 5G 了,但我为啥非得多弄点信息在每次请求中传来传去,jwt 是被迫无奈。
    aboat365
        29
    aboat365  
    OP
       2021-04-29 20:25:08 +08:00
    @xuanbg 方便分布式还真是 jwt 的优点,每个系统都配置一样的密钥,然后签出去的 token ,大家都能验证。但这个优点,cookie + session 也是有非常成熟的解决方案,一个 session 共享即可。既然业务做得那么大了,都搞分布式了,恐怕无状态的 jwt 方案都不一定能满足需求了。所以,何不用 cookie + session 方案,现成的、成熟的、历经考验的、不用写代码的。
    CODEWEA
        30
    CODEWEA  
       2021-04-29 20:34:14 +08:00
    1 、为了写简历
    2 、前后端分离,前端组件生命周期一体化用 jwt 很方便
    xcstream
        31
    xcstream  
       2021-04-29 20:55:32 +08:00
    为了解决 服务器超过 1000 的话 共享的 redis 压力大吧
    crab
        32
    crab  
       2021-04-29 20:56:31 +08:00
    app 因素
    LeeReamond
        33
    LeeReamond  
       2021-04-29 21:02:24 +08:00 via Android
    你的主题里的 jwt 常规用法根本是错的,可见 lz 没有 jwt 生产部署经验,自然会有疑问。jwt 无状态天生与容器和集群结合,为了附带业务状态,通常用黑名单代替白名单的方式,在高并发数下比 session 方案节约一个数量级以上的资源,你把 jwt 就当成 sessionid 在用,当然会产生为什么要有 jwt 的疑问
    Junzhou
        34
    Junzhou  
       2021-04-29 21:37:23 +08:00 via iPhone   ❤️ 1
    @emeab session 做横向扩展比较麻烦,比较依赖于特定服务器。如果多个服务器间共享 session 就更麻烦了
    aboat365
        35
    aboat365  
    OP
       2021-04-29 21:53:45 +08:00
    @xcstream 没错,无状态 jwt 方案性能更优,但这就变成有状态和无状态会话身份认证的对比了(上千服务器的 web 服务,就不要考虑哪个方案代码多少的问题了,重新造轮子不过是几个程序员几天 996 而已,不费什么力气)。既然讨论有状态无状态,其中必然各有长短,那就看具体需求了,在满足需求的情况下,自然选性能高的方案,毕竟服务器不便宜。
    micean
        36
    micean  
       2021-04-29 22:03:47 +08:00
    那得看身份验证是不是中心化的
    令牌续期的话,自然也还是 oauth 的那套了
    aboat365
        37
    aboat365  
    OP
       2021-04-29 22:12:59 +08:00
    @LeeReamond 你看的真准,我真没有 jwt 生产部署经验,甚至没有接触过什么高并发。诚然,无状态比有状态性能更佳,这是因不同方案侧重点不同造成,特别是随着并发量增大,这个差距应该成正比或指数拉大(我真的没有这方面的经验和具体测试数据,如有错,请指正并见谅)。但性能再好,也是要为真实需求而服务。如层主所言,无状态再加黑名单可满足层主系统业务需求,且是高并发服务,相对有状态能减少不少服务器钱的情况下,自然无状态方案佳。但如果只是一些微小服务,为什么那么多也用无状态 jwt 呢?而且发现不少开源软件和技术方案文章,把无状态 jwt 做成了有状态 jwt,这又何解?
    aboat365
        38
    aboat365  
    OP
       2021-04-29 22:22:35 +08:00
    @Junzhou session 共享在各个 web 服务器中应该都有比较成熟的方案,而且基本不用写代码,所以,比起写代码实现无状态 jwt,这一点都不麻烦。
    LeeReamond
        39
    LeeReamond  
       2021-04-29 23:21:02 +08:00
    @aboat365 一般合理的框架开发,不是引擎层面的,单纯讨论框架问题,一般都有集成的鉴权方案,因为太过常见,所以合理的解释就是企业各自有集成方案。毕竟部署实际上只需要对接一个分发服务而已,无论多大规模的服务,既然永远不会导致 performance 变差,同时又不需要多写代码,为什么不用呢,如果选 session,即使有万分之一的可能性这个项目做大了,日活上去了,难道到时候再改成可横向扩展的鉴权系统?
    labulaka521
        40
    labulaka521  
       2021-04-29 23:25:50 +08:00
    jwt 仔路过,写了一些 web 都是 jwt
    Biluesgakki
        41
    Biluesgakki  
       2021-04-30 08:54:44 +08:00
    讲道理 既然项目都用了 redis 还用 jwt 干啥。。。
    sutra
        42
    sutra  
       2021-04-30 08:58:00 +08:00
    这个问题我觉得应该分成两部分来讨论,一是服务端验证方案,是 JWT 那样的去中心化存储式的,还是类似 Session ID 那样的中心化存储。然而是和前端的通信协议,是 token 还是 cookie 还是 session……,其实和前端的通信协议没多少可以讨论的,不管是 cookie 还是 session 其本质都是一个字符串那样的 token 。
    siweipancc
        43
    siweipancc  
       2021-04-30 09:01:43 +08:00 via iPhone
    看一下分布式下的客户端 ws 链接列表怎么维护吧
    GooGee
        44
    GooGee  
       2021-04-30 09:14:59 +08:00   ❤️ 1
    (译)别再使用 JWT 作为 Session 系统!问题重重且很危险。

    https://learnku.com/articles/22616
    CallMeSoul
        45
    CallMeSoul  
       2021-04-30 09:20:21 +08:00
    什么年代了还用 session ?还在写 jsp ? php 和网页混合?前后端分离了解下,多端了解下。
    zzzmh
        46
    zzzmh  
       2021-04-30 09:34:16 +08:00
    首先篡改是不现实的,除非你有超算+顶级科学家+无穷的时间
    其次如果你服务器要接受超级高并发,就会发现 session 也好,redis 也好,炸内存。分布式是能解但成本捉急。
    jwt 是一个折中方案,不是完美方案,但解决 99%的情况没问题,剩下的 1%不管也好,redis 黑名单也好,都不会炸内存了
    aboat365
        47
    aboat365  
    OP
       2021-04-30 09:36:45 +08:00
    @GooGee #44 这是一篇很棒的文章,较为全面的质疑了 jwt 作为会话系统的优点。但我仍然没有明白,为何大家都在使用 jwt 作会话?
    aboat365
        48
    aboat365  
    OP
       2021-04-30 09:51:03 +08:00
    @LeeReamond @zzzmh #39 #46 超级高并发,高并发,或未来预期的高并发而选择使用无状态会话来减少服务器压力,这是一个值得进一步探讨的问题。如前回答 #37 所述,无状态性能更优(正比或指数或其它),但作为一个高并发架构,应该有具体的数据来支持。所以,能否分享一下达到何种量级后,无状态性能将显著超越有状态,或者说这将是一个制约系统响应时间的瓶颈。如果有这份数据,将很好的指导架构考量,来决定是否值得缺少有状态的优点,而拥抱无状态。
    aboat365
        49
    aboat365  
    OP
       2021-04-30 10:04:26 +08:00
    @zzzmh 关于篡改,根据上下文理解你的意思应该是破解 jwt,那确实如你所言,难以破解。但本主题并未说 jwt 容易破解,主题中所说篡改指的是修改了 token ,那么服务器用公钥便能分辨出这是改过的 token,从而实现了防篡改。
    zoharSoul
        50
    zoharSoul  
       2021-04-30 10:20:45 +08:00
    @aboat365 #28
    > 无状态 jwt 对比有状态的 cookie + session,整体代码量自然是前者少,而且看起来简单,但后者是作为标准具有广泛的实现,实际使用几乎不用写什么代码(开发者甚至不需理解其原理,现成的实现也能工作的很好)。

    re:
    这个你说反了, 移动端上要是用 cookie + session 这套机制要额外写很多代码, 并且复杂很多.
    aboat365
        51
    aboat365  
    OP
       2021-04-30 10:26:42 +08:00
    @zoharSoul #50 我未做过移动端开发,不知道移动端使用 session id 会比使用 token 复杂多少?但请你不要骗我。如果是真的,那这是一个考量点。
    EIJAM
        52
    EIJAM  
       2021-04-30 10:35:29 +08:00 via iPhone
    @zoharSoul 移动端把 sessionid 存在 local storage 里面,会用更多代码么?
    a728976009
        53
    a728976009  
       2021-04-30 10:43:53 +08:00
    因为 oauth 和 oidc 几乎已经成为行业的认证标准了,安全有顾虑你可以用 jwe 代替 jwt
    CallMeSoul
        54
    CallMeSoul  
       2021-04-30 10:44:03 +08:00
    @aboat365 cookie + session 是以前时代的标准啊,不是现在的标准啊,现在的标准就是 jwt,而且广泛实现啊,不然也不会这么多人用 jwt,你完全可以自己写个加密协议作为 token 的,就是用了 jwt 这么个标准,而且也是广泛认可的,才这么多人用。不管你承不承认,cookie+seesion 是逐渐淘汰了,jsp 你当我没说。
    zoharSoul
        55
    zoharSoul  
       2021-04-30 10:51:34 +08:00
    @EIJAM #52 首先, 移动端就没有 local storage . 其次, 既然你要手动存, 那存 sessionid 和存 token 的成本是一样的,
    也就不存在楼主说的 sessionid 不需要手动处理.
    zoharSoul
        56
    zoharSoul  
       2021-04-30 10:53:04 +08:00
    @aboat365 #51 你可以自己试一下啊, 麻烦的点我已经说过了,
    两个情况:
    1. 你想用 cookie 来保存, 这种情况下非常复杂, 尤其涉及多域名切换, 和 h5 共享登录状态等等.
    2. 如果你拿着 sessionid 当 token 存, 那这种情况下, 没有任何优势, 成本是一样的.都是手动处理.
    chhpt
        57
    chhpt  
       2021-04-30 10:55:47 +08:00
    JWT 和 Cookie 、Session 不是对立的关系,实际上往往是结合使用的。登录鉴权本质上是客户端需要有一个服务端认可的身份标识,而 Session ID 和 JWT 都是这样的身份标识字符,本质上来说区别不大,Cookie 也只是一种保存身份标识的手段。如果在签发 JWT 时加入身份信息,验证 JWT 后再验证身份信息,就变成了有状态的 JWT,就和 Session 没有区别了。

    JWT 本质上是一种加密算法,仅此而已,而使用 JWT 的原因大概只是因为它是一种通用规范,支持较好。
    kahlkn
        58
    kahlkn  
       2021-04-30 11:01:47 +08:00   ❤️ 1
    如果 jwt 真的那么好,那么你们会发现 各种开放平台,比如 微信三方登陆,阿里云的各种接口等应该都走 jwt 才对。 然而并没有,他们的 appSecret 也好 accessKeySecret 也好,没有一个走 JWT 的。 他们的量级够大把,他们的开发团队够强把,如果这个机制( JWT 的思路,毕竟大厂,也许会自己造轮子)真的好用,他们应该会用上才对。

    看看微信的 三方登陆,拿 appId 和 appSecret 去换 access_token (类 UUID 的字符串,其他参数不管)。然后其他接口比如 获取用户的信息的接口,是需要传入 access_token 的(这不就是类似于 session id 的机制嘛)。

    人家大厂还在用类似于 session id 那套,等哪天各种 各类的技术博客啥的(比如 美团技术团队 那个博客,还有一些大佬的博客)都强推 JWT 了,再考虑 JWT 把。
    HashV2
        59
    HashV2  
       2021-04-30 11:02:07 +08:00
    我也不想用 领导要求的
    a728976009
        60
    a728976009  
       2021-04-30 11:05:33 +08:00   ❤️ 1
    另外用 session cookie 做单点登录就十分恶心,大型的分布式架构上体验不佳。
    认证协议的发展是一个过程,从 session cookie -> saml -> oauth -> oidc,到现在流行的 idaas 服务,每一步发展都是有原因的,你不能倒退着来。
    当然这也不是说 session cookie 就无用武之地,session cookie 还有很多使用场景的。
    另外 jwt 是分为 jws 和 jwe 的,我们通常指的都是 jws,应该把它看成是一个 encode 方式,jwe 才是 encryption,但这些都不能和认证协议等价。
    a728976009
        61
    a728976009  
       2021-04-30 11:16:02 +08:00
    @kahlkn #58 阿里云有 oidc 服务的 https://oauth.aliyun.com/.well-known/openid-configuration,Google 更是用了 oidc 很久了,甚至还有一个 playground https://developers.google.com/identity/protocols/oauth2/openid-connect
    kahlkn
        62
    kahlkn  
       2021-04-30 11:19:29 +08:00
    我们的 分布式 应用场景,就是由 认证授权模块 统一生成一个 类 UUID 的 token,用户登陆成功后,返回给前端,反正前端看着保存呗,别弄丢就行了。 然后每次请求的请求头 都会带有 这个 token,至于多域名跨域问题? 后端配置哪些域名可以进来就好了。

    流量 -> 阿里云 LBS -> 业务服务器 Nginx -> 网关 (校验 类 UUID 的 token 是否合法,是否有访问这个接口的权限)-> 业务模块 (获取用户信息工具 根据 token 获取用户信息,并存入 threadlocal )

    如果用户信息存入字段,仅仅存入比如用户昵称几个字段,业务上不一定用得到,还得去查一次,如果都存,一些业务的用户信息敏感不敏感先不说,单纯数据量,就很多,上面的 获取用户信息我们设计的也是分段获取,即你要一个用户属性,会自动拉去一定的用户信息到 threadlocal 中,不全部拉去因为多,也不能保证都用到。

    是,jwt 是减少了 网关层面的 一次查询,也仅仅是 token 合法性校验的查询 省去了,但是 接口权限 校验还是要查的把。后面业务模块中获取用户信息大概率还是要再查一次的把。所以呢,JWT 最后还是变成了一个 类 session id 的东西。

    至于水平扩展,网关受不了了,加机器。业务模块受不了了,加机器。注册中心大概率不会受不了的。 想怎么加就怎么加,只要有钱就行。
    lldld
        63
    lldld  
       2021-04-30 11:19:37 +08:00
    因为 jwt 省钱, 省事.

    1) sessionId 的有效验证必须依赖后端查询, jwt 是通过计算来验证, 成本低, 速度快.
    2) jwt 可以添加一些不敏感的数据, 前后端都可以使用, 减少了查询, 成本低.

    sessionId 更安全, 但是有多少数据需要这么安全呢? 而且需要高安全性的数据和操作可以要求用户提供其他凭证的, 比如支付时提供密码之类.
    liuky
        64
    liuky  
       2021-04-30 11:20:57 +08:00
    最恶心 session, 相比于把 jwt 变成有状态, session 的滥用才是真真让人感觉到恶心的
    also24
        65
    also24  
       2021-04-30 11:24:31 +08:00   ❤️ 4
    @GooGee
    这篇文章,还有楼主的附言,实际上在对比都不是 JWT 和 session,而是 Client Side Session 和 Sever Side Session,各种所谓的优势劣势,也是这两种形式的 Session 的差异。

    而 JWT 在这个场景下,只是作为 Client Side Session 的具体实现和载体而已。

    我在之前的帖子里专门说了这件事,比较冗长,但还是建议看一下:
    https://www.v2ex.com/t/656457

    关于 Session 与 JWT 经常被拿来做对比这件事,也专门做了说明:
    https://blog.by24.cn/archives/about-session.html#cl-48
    SjwNo1
        66
    SjwNo1  
       2021-04-30 11:25:59 +08:00
    @a728976009 jwt 有方法可以无状态地实现单点登录吗
    h82258652
        67
    h82258652  
       2021-04-30 11:26:12 +08:00
    看需求看场景呗。session id 也是能存数据库的。jwt 性能高,对移动端友好,但做回收不好弄,得像上面说的弄 redis 黑名单之类的方案,就有额外的工程量。
    a728976009
        68
    a728976009  
       2021-04-30 11:30:53 +08:00
    @SjwNo1 #66 jwt 不是用来解决 sso 的,它是一种 encode 方式,你需要找的是 oidc,建议搜一下关键字 oidc sso
    Slin
        69
    Slin  
       2021-04-30 11:32:30 +08:00
    @kahlkn 楼主说的 session + cookie 和 JWT 的问题,前面这种方式基本都被淘汰了,JWT 的缺点很明显,其实大部分用 JWT 都没有用无状态特性,只是用来生成一个 token 里面携带了多一些的信息 并没什么不妥。
    EIJAM
        70
    EIJAM  
       2021-04-30 11:42:51 +08:00 via iPhone
    @zoharSoul 纯好奇,不用 local storage,那移动端用什么存 jwt 的?
    falcon05
        71
    falcon05  
       2021-04-30 11:51:28 +08:00 via iPhone
    无状态的 jwt 有很多需求无法满足,比如 revoke,有状态的 jwt 又不如 session 成熟
    kahlkn
        72
    kahlkn  
       2021-04-30 11:53:50 +08:00
    首先 阿里云 确实有 JWT 的应用,这个让我确实很高兴,毕竟终于见到 JWT 的大厂的应用场景了。就是 @a728976009 说的 oidc 。 https://helpcdn.aliyun.com/document_detail/93698.html

    然后 了解了一下 oidc,感觉 OIDC 和 OAuth 的不同,就是 用 JWT (这里的 JWT 指这种机制,毕竟不同的签名 /加密名称不同) 来做了 用户基础信息 的载体(比如 用户 ID 用户名称),用户的其他信息 还是需要 调用接口去取的。然后因为 OIDC/OAuth 都是用来授权,或者三方登陆的,没有普通业务场景那么多问题,直接 JWT 传过去来获取用户信息就好了。

    优势,原来 OAuth 需要 先获取到 access_token ,再去调用 接口 获取用户信息。 而 OIDC 直接 返回了 id_token ( JWT ) 和 access_token (可有可无看服务商),对于大部分 只需要 三方的用户 ID 和 用户昵称的 场景,这样一步就够用了。

    至于用 JWT 去获取用户信息这个场景,本来服务于三方授权这样一种业务,你不可能说为 access_token 之类的 还设计什么角色、权限、接口权限 之类的 rbac 那套玩意,毕竟三方授权对于调用者来说我仅仅需要该用户在你网站上的部分用户数据。所以 JWT 的方式其实相对来说 优于 类 session id 模式。

    而且那些把 JWT 用来业务系统中的一些问题,比如基本上都不会出现。
    aboat365
        73
    aboat365  
    OP
       2021-04-30 12:59:12 +08:00
    @also24 拜读了你的文章,写的真棒!特别是提出 Client Side Session 和 Sever Side Session,更加精准简洁的描述了本主题中讨论的问题。在文章中,我发现 Sever Side Session 似乎得到更为广泛的支持。但为什么在国内,Client Side Session 模式特别盛行呢(使用如主题附录中 jwt 的实现)?
    zoharSoul
        74
    zoharSoul  
       2021-04-30 13:04:46 +08:00
    @EIJAM #70 sp 啊, sqlite 啊, 等等,
    当然这也算广义上的本地存储
    wshcdr
        75
    wshcdr  
       2021-04-30 13:40:12 +08:00   ❤️ 1
    无论是 session 还是 jwt 其实就是解决一个问题, 服务端怎么去识别连进来的客户端,session 是 pc 时代的产物,现在移动端盛行了,jwt 更适合了
    sherlockwhite
        76
    sherlockwhite  
       2021-04-30 13:51:55 +08:00
    localstorge 是 web 里面的实现吧,到移动端这边,是不支持 cookie 、session 的,因为他不是浏览器,就没有必要非要上 session 。这没什么问题吧
    namelosw
        77
    namelosw  
       2021-04-30 13:59:51 +08:00   ❤️ 1
    我搞过挺多这个,其实我觉得别的因素都是次要的,作为主要原因说不通,主要的因素还是性能 / 横向扩展性。

    流量不大的时候我觉得 Session 更简单好用。JWT 实现后续功能的时候基本上都是各种 Hack 。

    JWT 流行主要因为 JWT 横向扩展性好,不浪费后端资源。

    像 Google 力推 OIDC 这种 SSO 方案思路也类似,目的就是 stateless,这样才比较容易对付亿级的用户。
    baiyi
        78
    baiyi  
       2021-04-30 14:06:19 +08:00
    想起了我几年前的提问帖子......《请教各位一个问题, 为什么 session 机制没有被 JWT 所取代?》

    现在 JWT 有了更多的使用场景,其实已经有很大的发展了。
    aboat365
        79
    aboat365  
    OP
       2021-04-30 14:19:39 +08:00
    @baiyi #78 搜索了一下,这就是一个镜像问题😁 https://www.v2ex.com/t/381996
    三十年河东三十年河西,现在是 jwt 流行了。
    index90
        80
    index90  
       2021-04-30 14:25:18 +08:00
    jwt 和 session 的最大区别是去中心化。
    现在 web 网站,登录时一个一个站点:account.xxx.com
    看视频是一个站点:video.xxx.com
    论坛是另一个站点:bbs.xxx.com
    如果用 session,那么所有站点都需要对接到一个中心化存储( redis )
    如果是 jwt,只需要验证签名就完事了
    lanlanye
        81
    lanlanye  
       2021-04-30 14:25:58 +08:00
    我个人看好 JWT 的原因是它无状态,不需要后端维护 Session,想一下当并发量极高的时候你的 Session 要怎么处理?
    zzl22100048
        82
    zzl22100048  
       2021-04-30 14:26:10 +08:00
    @kahlkn oidc 是认证协议( authentication protocol ),OAuth2 是授权协议( authorization protocol )
    karloku
        83
    karloku  
       2021-04-30 14:28:26 +08:00
    jwt 是一套信息传递机制. 并不是一套认证方案. 和 cookie 也不冲突你可以把 jwt 存在 cookie 里用.
    不用 cookie 做认证的原因很简单. 后端是 api 的时候用 header 而不是 cookie 对 xsrf 防御更好. 如果用 cookie 还得协调前后端做一套 xsrf-token 来进行防御. 而 header 只需要在 ugc 内容的过滤和呈现上防止 xss 出现就好.
    baiyi
        84
    baiyi  
       2021-04-30 14:39:45 +08:00
    @aboat365 #79 是的,现在 JWT 使用场景更多了,但也不能说 JWT 替代了 session,哪怕是 OIDC 中也不是用 JWT 格式作为 accesstoken 。服务端在有相应的场景下,该存的状态还是没少,其实是等同于 session 机制,只不过是原来 session + cookie 被现在的流行的认证格式取代了。
    otakustay
        85
    otakustay  
       2021-04-30 14:40:45 +08:00
    JWT 正是平衡签发和安全后的产物,你所谓的“很难平衡”其实是把安全当作一个无底限的高要求在看吧
    alexkkaa
        86
    alexkkaa  
       2021-04-30 14:46:17 +08:00 via Android
    这种适合无浏览器环境的场景, 浏览器环境下 cookie 绝对够用
    pkoukk
        87
    pkoukk  
       2021-04-30 15:08:59 +08:00
    有 sql 了为啥要有 nosql,有 redis 为啥还有那么多 mq,不是不能实现,而是有的时候用起来更顺手更合适而已。
    在“能否达成相同效果”这点上纠结就进入误区了
    kahlkn
        88
    kahlkn  
       2021-04-30 15:13:19 +08:00
    @zzl22100048 本质上都是用来做 三方登陆 的,都可以说是属于 认证 把(应该把)?。 OAuth2 第一步是 授权,第二部 根据 access_token 获取用户信息,不就算是 认证 嘛。 oidc 第一步 就返回了 id_token,而 id token 又包含有用户信息,所以称为认证。
    sonxzjw
        89
    sonxzjw  
       2021-04-30 15:16:16 +08:00
    jwt 确实存在楼主所说的弊端,但不如换个想法来解决如何
    随意说一个吧,身份认证应该不是 jwt 的弊端,身份认证是审查有没有你这个人,之后才有鉴权。
    所以即使 jwt 过期时间 1 万年也没有影响哒
    woostundy
        90
    woostundy  
       2021-04-30 15:40:19 +08:00
    为了解决 session 到底咋存的问题。
    jwt 的答案:客户端自己存,服务端只校验有效性。
    OldCarMan
        91
    OldCarMan  
       2021-04-30 15:43:43 +08:00
    @chendy 其实可以搞一个黑名单之类(想要踢的人,ip 等等之类的)的有状态缓存(或者持久化),然后每次解析 jwt 时,做一次黑名单的过滤,PS:不知道我有没有理解错你说的踢人。
    trlove
        92
    trlove  
       2021-04-30 16:08:28 +08:00
    @hronro 哈哈哈 这就是词性问题。jwt 的 T 是 token 不假 但是合起来 jwt 它就代表一个约定,jwt 整体就是一个名词。token 这个机制本身也是一个独立名词。所以合起来也没问题。用生活现象来举例就是公交站牌 假设有 A B站 C三个站点  ,你可以说我到A下了 也可以加个字说我到 A 站下了 同时 你也可以说我到 B 站下 亦或是 B 站站下 …… 只要自己觉得不别扭就行 哈哈哈哈。这个问题的源头在于定义 jwt 的人吧 token 这个常用词 集成到它的约定的命名方式里面去了。
    dorentus
        93
    dorentus  
       2021-04-30 17:50:25 +08:00
    @kahlkn 拿微信和阿里说事没有任何说服力。微信开放平台的 API 里面现在还有 JSON 和 XML 混用的呢,能学吗?
    Owenjia
        94
    Owenjia  
       2021-05-01 09:56:35 +08:00   ❤️ 1
    aboat365
        95
    aboat365  
    OP
       2021-05-06 10:22:10 +08:00   ❤️ 1
    @Owenjia 阅读了一下 paseto 官方介绍
    https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid

    其中罗列了 jwt 、jwe 、jws 的各种安全漏洞,paseto 的设计更为安全,有望替代 jwt 。最后在总结部分说明:
    Don't use JWT for session management, as discussed in other articles.
    请勿使用 JWT 进行会话管理,如其他文章所述。

    For secure sessions: Just use cookies over HTTPS. Cookies should only store a random identifier which is paired with a server-side persistent storage mechanism.
    对于安全会话:只需通过 HTTPS 使用 cookie 。Cookies 仅应存储与服务器端持久性存储机制配对的随机标识符。
    0xD800
        96
    0xD800  
       69 天前
    个人觉得 jwt 思想适用于后端微服务间的通信使用,这种情况下网关先鉴权然后用 jwtToken 在服务间使用 0.0 这样是不是好一点?
    aboat365
        97
    aboat365  
    OP
       68 天前
    @0xD800 看情况吧,一般服务间通信不需要再鉴权
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2965 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:10 · PVG 21:10 · LAX 05:10 · JFK 08:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.