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

发现很多人分不清 jwt 和类 session token 的区别?

  •  4
     
  •   xiaomada ·
    tangzhangming · 203 天前 · 9960 次点击
    这是一个创建于 203 天前的主题,其中的信息可能已经有所发展或是发生改变。
    起因是今天一个群里有兄弟问修改密码后 jwt 怎么失效过期问题,然后一个小伙子说现在所有的接口开发都是使用 jwt ,我一瞬间都有些怀疑是不是自己记忆错乱了,因为我自己向来是非必要不使用 jwt 的,主要是这玩意签发后不可控,而且我抓包过一些大厂的应用,基本没见过头部厂商使用 jwt 做客户端和服务端 API 认证的,服务端与服务端之间有一些,比如 OIDC 里的 jwt ,然后小厂商应用还是有不少用 jwt 的,但明显达不到全使用 jwt 这种说法,半壁江山都很难说。

    我质疑了这小伙几句,这小伙子居然嘲讽起我,让我不会走就别学跑,想想自己是不是天才,给我气麻了。

    然后我也懒得打嘴炮,决定自己求证一下,然后搜到的内容就更让我焦麻了,因为我理解的 token 是这样的有两种
    1 、Json web token (jwt)
    2 、类 SESSION 模型 Token (没有统一叫法,原理为自定义生成 token ,token 对应信息在服务端储存,一般 redis 中,原理基本与 SESSION 相同,只不过 session_id 变成了 token ,且不再由后端写入到 cookie 中)

    这两种 token 模式对客户端来说都区别不大,唯一的区别是 jwt 可以解读信息,2 不可由客户端解读。

    然后我搜到的帖子和讨论给我惊呆了,很多程序员分不清这两种 token 的区别,包括很多后端,令我错愕的好几点:
    1 、很多人固执的认为,session 是网页时代的东西了,现在的 spa 页面和 APP 都只能使用 jwt
    2 、分不清 token 本身有好几种实现模式。
    3 、有的前端虽然在使用 jwt ,但他们不知道 jwt 本身载了内容,也不会去解析,因为后端直接给他们一次签发几个月有效期的。

    这种感觉就像我之前发现很多人分不清前端和 web 前端的区别一样,我一直以为这些似乎是常识,但是突然好像发现并不是
    115 条回复    2024-01-25 09:08:06 +08:00
    1  2  
    cgpiao
        1
    cgpiao  
       203 天前 via Android   ❤️ 8
    各行各业的大部分本来就是半桶水。
    尤其是一直做重复工作的人。
    软件行业不自己研究,99%都学不到东西。
    就整天比语言,框架啥的。
    dlmy
        2
    dlmy  
       203 天前   ❤️ 1
    Redis + Token 方案适用于基于浏览器的应用,JWT 适用于内网鉴权和移动端 APP (适用于提供给服务端的 API ,由调用方主动生成,主动去维护,例如:IOS 登录、APNS 的 API )。

    这些道理我都明白,但是公司项目直接是 JWT + Redis 一把梭,直接变缝合怪。
    xuanbg
        3
    xuanbg  
       203 天前
    哈哈哈,这就是所谓的魔幻现实啦。爱怎么理解就怎么理解吧,自己把事做对就行了。
    eatgrass
        4
    eatgrass  
       203 天前
    程序员日常
    tywtyw2002
        5
    tywtyw2002  
       203 天前   ❤️ 6
    JWT 不是一种 Token 的 format 吗? RFC 在这里 https://datatracker.ietf.org/doc/html/rfc7519

    JWT 的 rfc 只是说了这种 token 的格式和验证算法。

    对于 token 是不是 revoke 这个不再 jwt 的设计范围内。


    就像 Cloudflare access 用 JWT 格式做鉴权,里面也有各种验证的字段,比如 app_session_hash 等等东西。
    https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/application-token/


    比较常用的是,后端可以对于重要的 API 根据 session 做二次验证啊。不重要的,直接验证 JWT 是不是有效就好了。
    nnegier
        6
    nnegier  
       203 天前 via Android
    我都是自己写 token ,jwt 这玩意儿怪怪的感觉
    nnegier
        7
    nnegier  
       203 天前 via Android
    反正就是加密解密嘛
    MrSheng
        8
    MrSheng  
       203 天前
    @nnegier #6

    token 跟加解密有啥关系?
    jonsmith
        9
    jonsmith  
       203 天前
    JWT ,含有可校验的用户信息,相比 Session ,不用二次请求认证服务器。在分布式系统里挺有用的,特别是高并发场景下。
    chendy
        10
    chendy  
       203 天前
    核心还是培训机构开始教 jwt 了…
    Nazz
        11
    Nazz  
       203 天前
    很多人只知道调 API 而不懂原理
    encro
        12
    encro  
       203 天前
    @dlmy

    现在都是前后端分离,所以都用 jwt 没问题,是正确的!!!
    skarner
        13
    skarner  
       203 天前
    1 、Json web token (jwt)
    2 、类 SESSION 模型 Token (没有统一叫法,原理为自定义生成 token ,token 对应信息在服务端储存,一般 redis 中,原理基本与 SESSION 相同,只不过 session_id 变成了 token ,且不再由后端写入到 cookie 中)

    =======================================================
    1 和 2 总体来说是一回事,1 只是 2 的一种特殊情况。
    这 1 和 2 中所谓的 token ,不过是用自己的方式去实现了一遍 session ,不同的是 1 对格式有规范,2 自由度更大
    strawberrydafu
        14
    strawberrydafu  
       203 天前
    OIDC 标准里其实说了 token ( jwt )的 revoke

    ```
    16.18. Lifetimes of Access Tokens and Refresh Tokens
    Access Tokens might not be revocable by the Authorization Server. Access Token lifetimes SHOULD therefore be kept to single use or very short lifetimes.

    If ongoing access to the UserInfo Endpoint or other Protected Resources is required, a Refresh Token can be used. The Client can then exchange the Refresh Token at the Token Endpoint for a fresh short-lived Access Token that can be used to access the resource.

    The Authorization Server SHOULD clearly identify long-term grants to the User during Authorization. The Authorization Server SHOULD provide a mechanism for the End-User to revoke Access Tokens and Refresh Tokens granted to a Client.
    ```

    可能只是很多实现没有做
    crysislinux
        15
    crysislinux  
       203 天前
    用户认证 jwt 确实没有 session 可控。不过 jwt 实现起来更简单也不需要保存在服务端某个位置,一般项目也无所谓了。
    maxssy
        16
    maxssy  
       203 天前
    @nnegier #7 严格来说无论是 token 还是 jwt 都不涉及加密和解密
    mayli
        17
    mayli  
       203 天前
    我理解 jwt=cookie+signature
    这样可以信任用户 session 不需要反复查数据库?
    8355
        18
    8355  
       203 天前
    99%的人没实现过 jwt
    cp19890714
        19
    cp19890714  
       203 天前
    jwt 被滥用了
    agagega
        20
    agagega  
       203 天前 via iPhone
    不只是部分程序员这样,各行各业各个地方都会有这种人,思考问题只能在第一层,不会过脑子。未必是因为他们对工作没热情,很可能他们对生活的其他方面也这样。
    Curtion
        21
    Curtion  
       203 天前   ❤️ 1
    就是因为 jwt 不能撤销,所以最终服务器又存了一份, 仍然又回到了 session 模式,不同的是 jwt token 不存储在 cookie 中. 还有就是把 session 单机存储集中化了
    chotow
        22
    chotow  
       203 天前
    假设用 HS 算法来生成 JWT ,那么取用户密码的哈希来作为 JWT Secret 的一部分,不就可以实现更改密码后自动撤销旧 JWT ?
    nnegier
        23
    nnegier  
       203 天前 via Android
    @MrSheng #8 不是解密验证消息来源的合法性吗。
    nomagick
        24
    nomagick  
       203 天前 via Android
    我现在的处理办法是 jwt 中放置 session token ,想验哪个验哪个,正常情况下两个都验,遇到外部系统验证不了 session 就只验证 jwt 签名
    fuchish112
        25
    fuchish112  
       203 天前
    jwt+redis 才骚,我都用 redis 了,为啥要用 jwt
    nomagick
        26
    nomagick  
       203 天前 via Android
    @nomagick jwt 中不是 session token 讲错了是 session id ,jwt 是明文的,不能直接给 token ,要用 jwt 的签名
    zpf124
        27
    zpf124  
       203 天前
    @encro 前后端分离和用 jwt 没有关系。
    前后端分离了,除非展示前端的 webview 不支持 cookie ,否则 session 依然可用。
    Courstick
        28
    Courstick  
       203 天前
    @chotow #22 那你这样不是与 JWT 不需要查询数据库的初衷违背了,每次都要一次用户密码
    nikenidage1
        29
    nikenidage1  
       203 天前
    个人觉得 jwt 比例是很高的,虽然很多大网站不是,但很多小网站都是啊,所以比例应该很高
    MrSheng
        30
    MrSheng  
       203 天前
    @fuchish112 #25

    jwt 跟 redis 有啥关系? 用 redis 后为啥不能用 jwt ?
    fredweili
        31
    fredweili  
       203 天前
    我以为这是干货帖,吐槽没什么意义
    c3de3f21
        32
    c3de3f21  
       203 天前
    每次看完这种帖后就觉得我是废物。
    zhazi
        33
    zhazi  
       203 天前
    我知道你很麻,但是你先别麻,

    据我所致有相当大一部分程序员连“RFC”都不知道是什么

    其实领导也不关心是 token 还是 session ,他只关心他自己

    打工的,犯不上生那么大气。
    dzdh
        34
    dzdh  
       203 天前
    如果我的 token 格式是 uid_appid_(md5(appkey+uid)) 呢? 一样可以解析。

    兹以为,JWT 就是承载更多内容的 TOKEN(JSON WEB TOKEN , 他有 token 这个字呢)
    ShuWei
        35
    ShuWei  
       203 天前
    @Curtion 你这说法不对,服务器存储一份,应对不了 jwt 不能撤销的问题,别用错了
    tyzandhr
        36
    tyzandhr  
       203 天前 via Android
    但感觉确实遇到的接口设计都用的是 jwt (大厂的
    MrSheng
        37
    MrSheng  
       203 天前   ❤️ 1
    @nnegier #23

    如果签名也算加密的话,那你的理解是正确的。

    实际上,JWT 并不是用来加密你传输的内容,JWT payload 是明文的、明文的、明文的,不要把任何敏感信息放入 payload 中。

    你完全可以在 header 中声明空白的“加密”算法,signature 部分留空,payload 使用你自己真正的加密算法加密,这时候的 JWT 就退化成了你所说的自己写 token 。
    adoal
        38
    adoal  
       203 天前   ❤️ 1
    所以程序员的高薪就是在吃平台红利
    justdoit123
        39
    justdoit123  
       203 天前
    分不清 token 、session 、cookie 这三者关系的,大有人在。其实很正常,不做 web 自然没太大必要了解 session 与 cookie 的关系,安全性 严肃性不高的场景,随便一把梭也是能用的。
    Curtion
        40
    Curtion  
       203 天前
    @ShuWei #35 我的意思是服务存了一份, 每次校验还需校验是否存在, 如果存在则走后续流程,如果不存在则直接拦截请求. 想撤销时就删掉服务器中的缓存, 这样能够达到使 jwt 无效的效果. 如果不增加状态校验的话除非 jwt 过期否则无法撤销
    a132811
        41
    a132811  
       203 天前
    1. JWT is just a token format, there are several common token formats, e.g., SAML token, Kerberos token.
    2. OAuth is an authorization protocol, it can use JWT or other token format.


    无论是 web/ios/android 还是 client 都可以用。
    zpf124
        42
    zpf124  
       203 天前   ❤️ 3
    针对楼主的疑问,遇到二把刀不论在什么行业都是常态,甚至我在某些领域也是二把刀,发表过错误的观点。

    -----------------------------------
    1.1 、jwt 原本指的是一种 服务端签发后不保存状态的用户凭据, 任意一个客户端偷到了这个 key 都可以代表他进行访问,服务端不特定存储某个 key 的针对性数据。
    1.2 各类 session id 方案,指的是一种服务端记录客户状态,然后客户端只传递一个随机生成的 session id ,服务端根据这个 id 从 map 中找到对应的登录状态数据。

    但现实情况是 流行的技术会随着它的拥趸将本来它不擅长的领域里的更合适的方案给挤掉,然后这些拥趸会为了让她更适应这个领域而改成个四不像。
    所以现在有些项目配置文件也都非要用 json 替换了,然后替换了发现没法写注释、并且嵌套多了人眼没法看了,就又根据 json 发明了个 toml 。
    觉得机械都是应该轮子移动的设计师们,设计走不平整路面甚至楼梯的机器也是安装的轱辘,觉得以前的机械腿太落后低效,都没人研究了,可轮子又确实不好用结果又给这个轱辘安装一个杠杆,整的像是腿和轮子的私生子。

    jwt 也一样, 本来需要限制多端唯一、风险用户踢退等操作的系统,也由于开发者觉得 session 是落后的过时技术,要追随主流流行技术而采用了 jwt , 然后又为了实现这些与 jwt 思想背道而驰的需求, 发明了 失效校验服务,服务端将所有签发的 jwt 都存起来记录他们对应的失效信息,以及那些不同的 jwt 对应同一个用户。

    这些人放弃了浏览器和服务端程序都支持了很多年的 cookie + sessionId 的 session 方式, 又自己手动实现了一遍 自定义的 通过 redis + mysql 的 session , 然后还美其名曰 jwt 的新用法。

    ------------------------------------
    2.1 、二把刀们的错误认知,spa 、app 还是传统网页和用 session 还是 jwt 没关系。session 诞生于旧网页时代, 现在许多人所谓的 jwt 只是另一种没有使用 cookie 的 session 技术,app 发送请求的方式或者某些 webview 确实无法使用 cookie , 但传的 url 参数(或 header)参数名叫 jwt 还是 JSSESSIONID 没什么区别。
    2.2 jwt 的 token 是有固定格式, 但 token 只是一个泛化的概念, 用服务器端的客户端连接序号 1 、2 、3 当 token ,还是用 md5(当前时间戳 + 用户信息) 都无所谓,甚至明文 也可以被称为 token 。
    2.3 这样的人其实不少,不局限于前端,许多后端都一样,jwt 对于对于他们而言都只是一个标记, 和 sessionid ,md5 的用户 id 一样,不会想着往里面放不敏感的有用信息,更不会考虑解析内容,这使用一个 redis (或服务器内存中 map) 的 key 。
    winnie414
        43
    winnie414  
       203 天前
    我的理解是 jwt 就是带信息的 token 用 redis 的话就可以自己用 uuid 生成一个然后把信息放在 redis 里,我更喜欢后者,前者 jwt 生成的太臭太长了,想踢用户下线非常麻烦,
    a132811
        44
    a132811  
       203 天前
    @a132811 手误按成提交了。。
    3. 一般 jwt 被设定成短期的 token ,利用过期时间让它失效。
    JWT+redis 是实现 revoke 的一种方案,这会丢失分布式的优势 ; 不过实践中,可以基于特定的 flag, 有这个 flag 才走 redis. 这样的“缝合怪”方案很灵活。
    anonydmer
        45
    anonydmer  
       203 天前   ❤️ 11
    一点点个人理解:
    1. 传输方式和传输内容是两个概念,早些年只有 web 端所以可以用 cookie 传,现在既要考虑 web 又要考虑 app ,所以一般不在 cookie 中传认证信息,而放在 header 或者 url 中
    2. 传输的内容可以是一种特定格式的,也可以是无意义的字符串;特定格式之一就可以是 JWT ,自定义格式通常是无意义的字符串
    3. 如果传输的是 JWT 格式的,得益于它的自包含特征,服务器端可以不依赖任何存储机制,实现 SNA 架构;但是特定格式的例如楼主所谓的 session token ,仍然需要一个共享的 redis 存储服务之类;在这点上采用 jwt 是有优势的。
    4. jwt 只是一个 token 格式,把生命周期的问题全部归到它头上是不合理的;不能因为大部分的滥用否定这项技术
    5. 解决 token 有效期过长的问题,业界通行的方法是 access token 加 refresh token 的方式,access token 的有效期很短,refresh token 的时间长;这两种 token 并没有严格的格式定义,采用随机串和 jwt 格式都是目前通行的做法
    6. access token 和 refresh token 的方案很成熟,但是很多人不按照这个标准来用,总是自己实现各种认证服务各种造轮子,然后再说 jwt 不行
    7. 修改密码让现有登录信息去失效这个问题,采用无状态的架构是比较难实现的(包含 refresh token 这种方式),因为在这个需求下时间本身就是一个状态属性;这个时候用 session token 这种需要中心式存储的架构来解决这个问题是合理的,但是反正架构都改了,总是要在服务端同这个存储中心进行交互的,这样即使是使用 jwt ,在里面再存储个关联到 redis 中的变量然后走和 session 一样的认证逻辑也可以了,只不过是多次一举而已。

    身份认证方案是个很有意思的话题,有各种方案和解决办法,各有各的优势和不足,例如 Rails 中很早就有将信息存储在客户端( cookie )而不在服务器端进行任何存储的方法,但是又实现了 session 机制的安全性和生命周期需求。
    leonshaw
        46
    leonshaw  
       203 天前   ❤️ 1
    把 JWT 当中一种减少查询的手段,JWT 里也可以嵌 session id ,需要时效的时候也可以去查询。
    afeiche
        47
    afeiche  
       203 天前
    我们组新来两位同事,一位是校招,一位是社招,校招写了一个校验逻辑,起名叫 Jwtxxxxx ,然后社招说不用 jwt ,自己生成一个 uuid 放到 header 里面,然后数据都存 redis 中,校招同事在原来的 jwtxxxx 中直接改了,等我看代码的时候,我还真以为是 jwt 呢。。。。
    momocraft
        48
    momocraft  
       203 天前
    JWT 可以不是明文的 套一层 JWE
    jianchang512
        49
    jianchang512  
       203 天前
    只要涉及网页的应用,使用 cookie+sessionid 总是可以的。
    大部分使用 jwt 的方式,只是纯粹的当成了 cookie+sid 的替换,其他模式一模一样。而 jwt 本身也承载不了多少东西,多说加个用户 id 用户名等,也减少不了几个查询
    opentrade
        50
    opentrade  
       203 天前
    jwt 不好踢用户
    BBCCBB
        51
    BBCCBB  
       203 天前
    要想后端能主动针对 token 过期, 都得有一个白名单/黑名单的机制, 能识别哪些 token 有效, 哪些无效,

    这种一般都是用 redis 来缓存这些 token. 通过白名单/黑名单的方式来让 jwt/token/sessionId 过期.
    tywtyw2002
        52
    tywtyw2002  
       203 天前
    @mayli 这个理解是对的

    其实看业务了。

    k8s 类微服务,最前端的 nginx 和 WAF 来验证 signature 。 只有 signature 过了,才转发流量到后端服务,这样可以,减轻后端服务压力。

    后端还是改验证就验证,反正 JWT 里面可以包含非常多的字段。

    JWT 只是一种格式,不是验证方式,用 JWT 的签名当作鉴权,其实并不是很好。
    nbndco
        53
    nbndco  
       203 天前
    想到之前某项目,上了 JWT ,又说为了 compliance 必须要能 revoke ,只好又用 jwt 去存 session id 。最终系统同时获得了 jwt 和 session 的全部缺点。
    mxT52CRuqR6o5
        54
    mxT52CRuqR6o5  
       203 天前 via Android
    Jwt 好处是不需要一个中心服务去校验认证信息,验一下签名就行。如果非要用 jwt 去实现主动失效的话,无非就是用了一种很别扭的方式重新实现了一遍 session ,那既然如此为啥不直接用 session 呢
    42is42is42
        55
    42is42is42  
       203 天前
    在分布式系统中共享信息,CAP 就不可兼得,所以分布式环境中的状态管理一定会受到 CAP 的局限,无论怎样都不可能完美。但如果只是解决分布式下的认证授权问题,并顺带解决少量状态的问题,就不一定只能依靠共享信息去实现。JWT 令牌与 Cookie-Session 并不是完全对等的解决方案,它只用来处理认证授权问题,充其量能携带少量非敏感的信息,只是 Cookie-Session 在认证授权问题上的替代品,而不能说 JWT 要比 Cookie-Session 更加先进,更不可能全面取代 Cookie-Session 机制。
    Masoud2023
        56
    Masoud2023  
       203 天前
    年轻时不懂 jwt ,成长时赞赏 jwt ,成熟后唾弃 jwt 。
    ZeroDu
        57
    ZeroDu  
       203 天前
    p 理解没问题; jwt 很多人用的就有问题,为了踢人引入 redis ; jwt 中如果包含信息,修改有也无法及时更新。
    大多是后 session 有效可用的。很多项目使用的是:登录时自定义一个唯一值(暂且称为 token/一个标识),写入 cookie ,然后请求携带,这就是类 session 的实现。
    很多项目把"token" 通过 header 传递来,应对有些地方 cookie 支持不方便
    woodfizky
        58
    woodfizky  
       203 天前   ❤️ 1
    JWT 只是 token 的一种格式,就好比坐地铁的临时代币 token ,JWT 可以在 token 里加时间、用户等的 payload ,再根据这些 payload 生成一个签名,防止 payload 被篡改,服务端也可以根据 payload 做一些简单的判断,比如登录态过期、JWT 被篡改等;

    session 是服务端维护的一个东西,需要和用户的 token 对应,不管这个 token 是用 cookie 还是 header 的形式携带,也不管用的什么格式,到了服务端的主要目的还是确认用户实际上对应服务端的哪个 session ;

    单纯只用 JWT 做用户验证/鉴权,没法避免 token 被盗用的情况(类似地铁代币被偷),也没法避免 token 被多用的情况(代币被复制)。
    dqzcwxb
        59
    dqzcwxb  
       203 天前
    RESTFul JWT 中台 DDD FaaS IOT 区块链 AI ServiceMesh Low-Code
    以上技术名词出现一两个是正常的,如果出现三个以上那么就要注意了
    cp19890714
        60
    cp19890714  
       203 天前
    首先,我认同你说的。
    个人看法,各种会话方案其实都差不多,就是把各种理念进行不同的组合,形成各种方案,常用的方案被作为标准,进行命名。没必要在意这些方案究竟属于哪个概念,只要契合当前需求就行。
    但是明显反感不契合需求,还强行用,那可不好。现在很多人用 JWT 就属于 拿着锤子看什么都是钉子。
    encro
        61
    encro  
       203 天前
    @zpf124

    vue,react 等都是直接请求获取 token ,然后根据 token 取数据,当然没必要再搞一层 session 。
    pkoukk
        62
    pkoukk  
       203 天前
    培训机构教歪了
    nobodyknows
        63
    nobodyknows  
       203 天前
    我看 Apple 和 Google 的一些服务 API 都用 jwt, 他们算头部大厂吗?
    cheng6563
        64
    cheng6563  
       203 天前
    可以了,我面的,一堆不知道 JWT 可以离线验证的。
    一堆不知道除了 JWT 还可以用(类) SESSION 的。
    ihciah
        65
    ihciah  
       203 天前
    用 jwt 不是挺好嘛,格式标准,自带可被校验的元信息。对于只依赖这部分信息的中间件可以省去捞缓存/数据库的开销和瓶颈。不想用户可读,payload 还是可以存放某种 id ,后端再去自己捞。需要即时过期,可以对 payload 做额外后段验证,或者签发时效较短的 jwt 。尽信书不如无书,原理很简单,看情况用即可。
    manasheep
        66
    manasheep  
       203 天前
    jwt 很方便啊,有安全顾虑就签短时间的 token ,不就完了么
    whrss9527
        67
    whrss9527  
       203 天前
    jwt 是无状态的,对于签发给用户个人使用,颁发 jwt 可以极大地节约请求量和并发,在安全性上也足够有保障。
    对于服务端存储 token 或者 session ,可以保障的是即使内部代码泄露、配置泄漏,用户的 key 是实时计算出来的,保证一些意外情况下的“安全性”。
    以上都是在合理情况下的使用,非合理使用比如在明文处传递敏感信息等不在考虑范围。
    lambdaq
        68
    lambdaq  
       203 天前
    不是很懂。jwt 不就是随便存一堆数据+签个名么。。。而且 revoke 的原理就是弄一个时间很短的 access_token 。。你下次用 refresh_token 去刷新,就拒绝。。。。

    > 这两种 token 模式对客户端来说都区别不大,唯一的区别是 jwt 可以解读信息,2 不可由客户端解读。

    正确的。
    xiaomada
        69
    xiaomada  
    OP
       203 天前
    @nobodyknows 那是给第三方调用的多 你抓包看他自己的应用有几个用 jwt 的
    gongshuiwen
        70
    gongshuiwen  
       203 天前   ❤️ 4
    巧了这两天刚好在研究认证方式的问题,照着网上铺天盖地的教程用 SpringSecuriy 实现了一下 JWT 认证方式,发现使用完全无状态的 JWT 认证的场景十分有限,最大的缺陷就是无法主动过期,而且要实现由用户主动下线已登录客户端的功能就必须要引入 Redis 来存储分布式 Session ,那其实就跟基于 Cookie 的 Session 没啥大的区别了,只是前端存储方法不一样而已,相较之下基于 Cookie 的 Session 有大量成熟的框架可以使用,而基于 JWT 的 Session 大部分功能还要自己开发,最后我还是老老实实用基于 Cookie 的 Session 了哈哈哈。贴两个关于这个问题的经典帖子,想辩论的建议都看下先:

    http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
    http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/

    附注:
    关于 JWT 携带 SessionId 可以防篡改的功能,其实基于 Cookie 你一样也可以给 SessionId 加个签名后缀,自己实现一下 SessionId 的生成逻辑就行。
    xiaomada
        71
    xiaomada  
    OP
       203 天前
    @gongshuiwen 你转发的这个帖子很好
    zpf124
        72
    zpf124  
       203 天前
    @encro

    你提到的前端框架里如何使用 jwt 只是流行程度高的一套最佳实践而已,只是现在更流行而已不代表只能如何或者这种方式什么场景都有优势。
    vue,react 你如果想找也一定可以找到使用 sessionid 保持会话的方式,区别只是你用 jwt 时 是 jwt 这个字符串可以拆分出来一个 json ,里面可以解析到一部分用户信息,而使用 sessionid 时 可能会有 另外一个叫 userinfo 的 json 串保存这些通用数据给你们前端,或者干脆有 4 、5 个不同的 cookie 分别叫 username ,head_img ,当然用 localstorage 也一样。


    然而 jwt 的 token 只能存放不敏感且通用的数据,比如用户名,昵称这种。 其它像某个子模块下的具体信息,还有敏感信息是不应该存在 jwt 里的, 比如某个子模块下的菜单顺序,手机号,身份证号,密码加密串,当你需要操作这些数据的时候,jwt 和 session 方式没有区别, 只是 jwt 是传的一个 特定格式的字符串,而 session 传的是某种服务端生成的随机字符串, 对于服务端来说 这都仅仅是一个 证明 “你是你” 的 ticket 。
    ersic
        73
    ersic  
       203 天前
    我也不喜欢 jwt ,chatgpt 好像就是 jwt
    wansho
        74
    wansho  
       203 天前
    所以你不用 jwt ,那你用的啥啊,你也没说啊
    encro
        75
    encro  
       203 天前
    @zpf124

    两者不是一样的,vue/react 单应用如果采用 session id 就多了中间层,token 是无中间层的。

    session id: browser->frontend server(负责生成 session id)->backend server
    json web token: browser ->backend server(负责生成 token)


    如果你想:

    session id: browser->backend server(负责生成 session id)

    那么 session id 又得变成了 token ,否则就是不安全的。。。结果又成了 jwt(json web token)

    所以 jwt 只是 json web token 而已。。。

    只是一种 web token 方案而已。。。
    Seulgi
        76
    Seulgi  
       203 天前
    jwt 是 jwt ,jwt+redis ,是因为某些公司在用 redis 做状态,jwt 本身可以说是无状态的,登录登出是无法直接在 jwt 上体现。
    至于说的 session 其实本质是为了不暴露信息,相当于给出去一个 key ,云端还要自己做 k-v ,当然这个 k 又经过各种加密算法加持什么的,可以带上一些标识实现一些功能。所以这类在设计上就需要一个 k-v 存储器。
    xiaomada
        77
    xiaomada  
    OP
       203 天前
    @wansho 你这是属于现身说法了
    wanguorui123
        78
    wanguorui123  
       203 天前
    jwt 无状态鉴权
    session cookie / tokenId header 有状态鉴权
    ggymm
        79
    ggymm  
       203 天前
    @xiaomada 其实很多人说的有点问题,jwt 不单单是一种特殊的 token 。关键还在于 jwt 模式中很关键的 refresh_token 机制。就是 jwt 模式中有个比较关键的续签机制。基于此 jwt 更适合在 oauth2 使用。而非 cas
    IvanLi127
        80
    IvanLi127  
       203 天前 via Android
    习惯就好... 另外 jwt 可不可控,和你怎么用有关系。
    gps949
        81
    gps949  
       203 天前
    我觉得这篇还成啊: https://cloud.tencent.com/developer/article/1680180

    JWT 本质上算是 Token 这种鉴别-授权方式机制的特例(特定实现)
    我甚至认为 Token 这个词含义过广,比如 Cookie-Session 机制也可以看做基于 Token (令牌)的吧?感觉我的这种理解下,Token 一词已经泛化到了全部用于鉴别( Authentication )的凭证( Credentials )了。

    另有一个这个: https://gist.github.com/john-raymon/23e5bf6cf228effc9c32918c5ab14fbd
    hongfs
        82
    hongfs  
       203 天前
    @MrSheng #30 没关系,但大多数不会这样子使用,如果非要使用,还需要对 jwt 进行 sha1 之类操作,减少长度。
    zpf124
        83
    zpf124  
       203 天前   ❤️ 2
    @encro

    不知道你的 frontend server, backend server 是什么东西, 反正和我的理解完全不一致,你真的经历过 session 时代吗?


    我的认知里的前端服务器主要是用来做服务端预渲染,那么它实际作用和代理类似, 只转发请求和返回 backend 的数据就好了, 为什么要在这生成 sessionId ,并且我也没理解你这里生成的 session id 是怎么办到可以去 backend 通过鉴权的。


    session id:
    1 、登录 browser->frontend server(无 SSR 需求的可去掉)->backend server (实现登录并返回 sessionid )
    2 、操作某数据 browser ( head 包含 session id )->frontend server ->backend server
    3 、获取通用展示数据 browser ( head 包含 session id )->frontend server ->backend server
    或 从登录后的写入的某自定义 cookie 中读取。

    jwt:
    1 、登录 browser->frontend server(无 SSR 需求的可去掉)->backend server (实现登录并返回 jwt )
    2 、操作某数据 browser ( head 包含 token )-> frontend server ->backend server
    3 、获取通用展示数据, 从 jwt 的 payload 中解析部分字段,不发送请求

    我不理解你的思路,没明白你在做什么。

    在我的描述的中
    2 是用 session id 还是 jwt ,效果有什么不一样吗?替换使用有什么区别吗?
    3 两者略有差异,但这差异大吗? 即便是无法使用 cookie 的场景,session id 的使用方式也只需要第一次多发一个获取通用信息的接口,然后和 session id 、jwt 存储到同一位置,以后使用一样是客户端本地读取。
    expy
        84
    expy  
       203 天前
    给 jwt 加上服务端状态管理,重新发明一下 session 。
    fovecifer
        85
    fovecifer  
       203 天前
    JWT 可以去中心化,但是注销问题一般又会引入中心化节点
    普通 session 还是中心化的,不太容易横向扩展
    Torpedo
        86
    Torpedo  
       203 天前
    楼主可以再试试问 sso🐶
    lanlanye
        87
    lanlanye  
       203 天前
    奇怪,我倒是觉得所有不严格需要“立刻过期“的场景都应该优先选择 JWT ,尤其是涉及分布式的时候,毕竟它最大的好处是验证不需要访问任何外部的鉴权服务/DB (包括 Redis )。

    至于安全方面的考虑,有效期短一点,配上合理的刷新机制就可以了,修改密码这种场景取消掉刷新用的 Token 就可以了。
    night98
        88
    night98  
       203 天前
    我都习惯了,还有些骚操作直接发十年的 jwt ,然后 redis 再存一份,嗯,简直完美,啥都能实现
    z3k3
        89
    z3k3  
       202 天前   ❤️ 2
    觉得概念太混乱了,说说自己的理解。

    ---

    这一切都起源于一个需求 —— 会话管理。

    大家都知道 HTTP 协议是无状态的。为了能在 HTTP 协议之上保持状态,引入了 Session (会话)的概念,它只是一片「可以把无状态的 HTTP 请求关联起来」的数据。

    需要注意,Session 只是一个抽象的概念,它不与特定实现绑定。在各种特定的实现里才涉及到那些名词 JWT 、JWE 、Cookie 、HTML5 Web Storage 等等。

    会话管理需要从 4 个层次来设计。

    ## Session 的序列化方式

    Session 在服务端与客户端之间传递,必然会涉及到序列化方式。序列化方式有很多:

    *可以自定序列化方式,通常会涉及编码、加密、签名。
    * 可以使用现成的标准,比如 JWT 、JWE 等。

    ## 服务端与客户端的协作模式

    模式 1 - 服务端不存储 Session ,它将序列化后的 Session ,发送给客户端:
    * 优点:
    * 服务端不存储 Session ,默认就有很好的横向拓展性。
    * 缺点:
    * 通常情况下,客户端的存储空间受限(比如 Web 浏览器的 Cookie ),不适合 Session 相关的数据比较多的场景。

    模式 2 - 服务端存储 Session ,它将序列化后 Session 标识符(而不是 Session ),发送给客户端:
    * 优点:
    * 服务端保存 Session ,没有存储空间受限的困扰。
    * 服务端可以直接操作 Session 。
    * 缺点:
    * 在横向拓展上需要多付出一点努力(但也都有成熟的解决方案)。

    ## Session 在客户端中的存储方式

    以 Web 浏览器为例,存储方式可以是:

    * Cookie - 易受 CSRF 攻击,但可以使用 CSRF Token 防御。
    * HTML5 Web Storage - 易受 XSS 攻击,受攻击面更大。

    ## Session 在服务端中的存储方式

    存储方式可以是:
    + 关系性数据库:PostgreSQL 、MySQL 等。
    + 非关系型数据库:Redis 等。
    + 缓存:Memcached 、OTP 提供的 ETS 等。
    + ...

    ## 具体实现

    知道了上面这些,就可以随便针对特定场景来做设计。

    针对常见的 Web 应用:
    + Session 的序列化方式:base64 做编码,fernet 做加密,hmac 做签名(想偷懒的话,找个包调一下)。
    + 服务端与客户端的协作模式:没有复杂的需求,就选模式 1 吧。
    + Session 在客户端中的存储方式:既然是浏览器,就选 Cookie 。
    + Session 在服务端中的存储方式:选了模式 1 ,啥也不用存。

    针对 SPA:
    + Session 的序列化方式:你们都说要 JWT 好,那就 JWT 。
    + 服务端与客户端的协作模式:偷懒,选模式 1 。
    + Session 在客户端中的存储方式:前端不会调 Cookie 的数据?那就用 HTML5 Web Storage 。
    + Session 在服务端中的存储方式:选了模式 1 ,啥也不用存。

    针对复杂的 Web 应用(需要实现会话强制过期之类的功能):
    + Session 的序列化方式:找个包调一下。
    + 服务端与客户端的协作模式:不得不选模式 2 。
    + Session 在客户端中的存储方式:Cookie 。
    + Session 在服务端中的存储方式:业务数据库用了 PostgreSQL ,那就用它吧。

    把概念的层次搞清楚,想怎么整都行。
    Rorysky
        90
    Rorysky  
       202 天前
    这才是 创意者社区的 意义
    whileFalse
        91
    whileFalse  
       202 天前 via Android
    核心区别就是是否能够脱离服务端验证。
    能够脱离服务端验证,服务端就无法轻易吊销。
    whileFalse
        92
    whileFalse  
       202 天前 via Android
    @chotow 然后你每次用 jwt 的时候都让用户输一遍密码?
    mmdsun
        93
    mmdsun  
       202 天前 via iPhone
    @MrSheng jwt 本来就是去中心化,过期时间存 jwt 里面由客户端携带,服务端不存省内存,缺点就是服务端不能主动过期 token 。 还用 Redis 就很奇怪了
    MrSheng
        94
    MrSheng  
       202 天前
    @hongfs #82

    将 JWT 计算哈希值之后放入 redis ,再次请求的时候判断是否可以命中 redis 缓存,是这样使用的吗?

    如果是这样的话,恕我直言,这就是垃圾,早早远离的为好,因为 JWT 校验可以在本地完成,根本不需要请求网络。

    如果不是这样的话,那是怎么配合使用的?
    encro
        95
    encro  
       202 天前
    @zpf124

    或许你的理解也没错,jwt 就是不依赖 cookie 的 token ,sessionid 依赖 cookie 的 token 。

    因为 jwt 不依赖 token,后端可以写一套接口,适用 web,app,小程序,

    这就是 jwt 大行其道的原因。
    hongfs
        96
    hongfs  
       202 天前
    @MrSheng #94 加了一层 redis 是为了实现 退出 功能,jwt 不需要网络就可以完成校验,当你想拉黑一个用户之类,就必须使用到存储了。

    jwt+redis 模式,你可以利用 jwt 特性先校验然后再进入 redis 层面。我并没有验证过这样可以缓解多大的 redis 压力或者提升多少的性能,但和实现的复杂程度相比,真的有收益吗。
    encro
        97
    encro  
       202 天前
    @hongfs

    往往 redis 只是为了分布式负载均衡。
    dyllen
        98
    dyllen  
       202 天前
    jwt 不可控,要做踢下线的功能,修改密码过期都搞不了,有这种需求的还是自己生成个 token+redis 来吧。99%的应用省那么点查询没任何影响。
    zpf124
        99
    zpf124  
       202 天前   ❤️ 1
    @encro

    然而你这部分理解还是有问题,
    sessionid 并不一定非要 cookie 才可以,只是 cookie 默认就会携带无需前端做什么。

    以 Java 语言的 tomcat 服务器为例,session 的字段叫 JSSESSIONID , 服务端首先会从 cookie 里尝试读取, 读取不到,会尝试从 header 里读取,还读不到会再从 url 参数中尝试读取, 都没有的情况下,才会认为这是一个新的会话,会生成一个新的 id 。

    所以, 在不支持 cookie 的环境下,jwt 也得通过代码实现,从 localStorage 或者其它本地存储中读取并添加到,header 中,而 sessionid 自然也可以这么干。


    jwt 的真正优势是, 服务器不需要存储会话信息, 不需要联机校验, 当 jwt 携带的 hash 与内容校验一致就可以认为是该用户,然后直接判断权限,操作数据即可,操作完了也不需要保存这个用户任何信息,下次新用户来了再重新做一次 jwt 校验就行。

    然而许多蠢人盲目随大流或者有些人怀着练习新技术的想法, 使用 jwt 作为 session Id 又重新实现了一遍 session 管理,把 jwt 弄成了 session 的形状,等于是放着默认已经支持的 session 实现不用,自己手写代码实现了一遍。

    在这种环境中,jwt 只是一个去 redis 或者 mysql 获取数据的 key , 检查 jwt 完整性屁用没有, 还得去查相关的库表,确认该 “token” 没有失效后,再加载这个 jwt 对应的在服务端保存的缓存数据(这个东西在原来的实现里 我们称之为 session )。

    甚至有些后端还会在这一步给这个 jwt 客户端签发一个 sessionid ,这样下次这个 jwt 客户端就可以不用再走上面的校验流程了。
    在给 jwt 套上一层 session 管理后, 又为某段时间内某个客户端添加了默认的 session 实现,对于这种夹心饼的嵌套做法,看的我实在是叹为观止。
    tomwu618
        100
    tomwu618  
       202 天前
    非单体或者异构系统中 token+redis 适用范围最广最为均衡

    jwt 相对于 session 有两个目标
    1 、jwt 同时满足 token 和认证信息的表示,形象来说一路请求传递多种信息,session 却只能起到 token 的作用
    2 、jwt 满足无状态服务的设想,可以任意负载均衡请求但是丧失了管控能力,相对于 session 有点选择 AP 放弃 CP 的意思

    为什么选择 token+redis ?
    1 、既然 jwt 同时满足 token 和认证信息两方面追求,我们大可返过来实现,认证成功后返回包含 token 的认证信息,服务端透过 redis 维护 token ,即不提 jwt 但是也干了同样的事
    2 、分布式系统跑 stream 的不算,业务类的必然有同步的点,etcd 、各种分布式锁、队列实现等等都说明这点,因此引入 redis 尤其是分片模式保存认证状态,是无需纠结的事,意思是如果使用 redis 这样的中间件没有在架构层面预先决策,而是实现登录时才想到,那说明你的系统没有这样的基因,是否使用 jwt 如何使用大可随意
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2806 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 12:09 · PVG 20:09 · LAX 05:09 · JFK 08:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.