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

谁能用简短的语言解释 JWT 和 session 的区别?

  •  1
     
  •   chaleaochexist · 2018-10-10 14:15:42 +08:00 · 8829 次点击
    这是一个创建于 2268 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我目前的理解是.

    JWT 在服务器端只需要验证你的 token 是正确的就可以.也就是说数据库里面只需要保存类似这种.

    user_id token

    然后服务器接到 token 信息,就知道你是谁了.剩下的信息也都在 token 里面装着.不装在服务器端.

    要不然我理解不了 JWT 方式和 session 的区别.

    53 条回复    2018-10-12 00:34:43 +08:00
    jswh
        1
    jswh  
       2018-10-10 14:26:14 +08:00
    session 是存在服务器端的,是服务器端对客户端的访问状态的存储,因为 HTTP 本身是无状态的,但有时候有需要保存状态(比如登录状态),就用这种方式,一般配合 cookie 来使用。token 是访问令牌,就是一种权限的校验机制,JWT 是 token 的一种规范。这里面的概念都不一样,不能这么比。
    rainonline
        2
    rainonline  
       2018-10-10 14:29:42 +08:00
    JWT 是不需要数据库的。当服务器授权生成 Token 之后,用户存储在浏览器中,服务器本身不储存用户的状态。访问服务器时服务器直接算法校验用户传过来的 Token 是否有效。不过这样有一些缺点比如不能服务端设置 Token 无效,只能等他过期。

    Session 则是用一个全局变量来存储用户的状态。长期保存需要存储在数据库中,多个服务共享登陆状态时还要做 Session 数据共享等操作,可扩展性差一些但比较容易做控制
    zsh1995
        3
    zsh1995  
       2018-10-10 14:30:58 +08:00
    理论上 JWT 的 token 也不需要存数据库吧,验证是基于密码学的签名算法的
    tachikomachann
        4
    tachikomachann  
       2018-10-10 14:36:32 +08:00 via Android   ❤️ 1
    jwt 也是 session 的一种
    传统的 session 验证方式是服务端有存储介质保存用户 session,客户端请求时带上票据来服务端验证。
    jwt 基于一套标准的加密方式,加密票据和 session 信息(比如登录用户的数据),并且不需要存储介质就能验证票据合法性,可以做到 session 产生后不需要服务端参与验证。

    当然,缺点也很明显,只依赖客户端的话,jwt 无法集中控制用户会话过期,比如后台踢出用户这种操作。
    qq976739120
        5
    qq976739120  
       2018-10-10 14:44:50 +08:00
    我现在是登录的时候生成一个 uuid 放到缓存,前端放到 cookie,redis 里 uuid: 用户信息,然后每次访问的时候前端带这个 uuid 过来,缓存里判断是否存在这个 uuid,存在这个 uuid 表示登录. 感觉也蛮方便的
    precisi0nux
        6
    precisi0nux  
       2018-10-10 14:46:54 +08:00 via iPhone
    @tachikomachann 这也是我一直疑惑的,如果用户改密码了,如何去 invalidate 那个 jwt token。
    mgcnrx11
        7
    mgcnrx11  
       2018-10-10 14:50:19 +08:00
    这个写得挺好的,http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/ 。不过不是楼主要的简短的
    sunnysen
        8
    sunnysen  
       2018-10-10 15:19:19 +08:00
    明显两个概念 维基一下就知道了 前排别误人子弟
    imn1
        9
    imn1  
       2018-10-10 15:26:19 +08:00
    session 是一个环境、变量容器,不能把它其中一个用途 /属性抽出来代替它
    crab
        10
    crab  
       2018-10-10 15:30:02 +08:00
    @precisi0nux jwt 带上过期时间,过期要重新请求了。
    571726193
        11
    571726193  
       2018-10-10 15:40:26 +08:00   ❤️ 1
    @rainonline 你好 之前使用过 jwt,但是 道理不是太懂,以下几点能否指点以下:
    1,JWT 生成的 token 存放在哪里啊?
    2,移动端登录到服务器返回一个 token, 以后每次访问都带着这个 token 来请求接口 ,服务端是通过什么知道 带上来的 token 和 第一次生成的 token 一样的?

    菜鸟一枚,真心求教 谢谢大佬
    qwx
        12
    qwx  
       2018-10-10 15:51:58 +08:00
    @571726193
    1、生成的 token 应该传递给客户端存放在客户端
    2、我的操作是整个 token 放到 redis,提交上来先验证,当然有大佬告诉我最好不要这么做。
    (虽然 token 的验证是通过签名来保证不可伪造就是了)
    leafin
        13
    leafin  
       2018-10-10 16:02:00 +08:00
    @571726193 简单理解一下:在 session 机制下,当用户登录时,服务器从数据库读出用户信息
    leafin
        14
    leafin  
       2018-10-10 16:08:14 +08:00   ❤️ 1
    @571726193 简单理解一下:
    在 session 机制下,当用户登录时,服务器从数据库读出用户信息,把用户信息保存在 session 容器里,然后创建一个 sessionId 指向这个用户信息。然后把 sessionId 返回给客户端保存。下次客户端请求时带上 sessionId,服务器查找 sessionId 对应的 session,即可得到用已认证的户信息。
    可以理解成服务器创建并保存会员卡,然后把卡号告诉你。你要消费的时候提供卡号就行。

    在 JWT 机制下,当用户登录时,服务器从数据库读出用户信息,把用户信息加密生成一个 token。然后把 token 返回给客户端保存。下次客户的请求时带上 token,服务器解密 token,从中得到已认证的用户信息。
    可以理解成服务器创建会员卡,然后把卡给你。你要消费的时候要提供会员卡。
    571726193
        15
    571726193  
       2018-10-10 16:08:32 +08:00
    @leafin 1,JWT 生成的 token 存放在哪里啊?
    2,移动端登录到服务器返回一个 token, 以后每次访问都带着这个 token 来请求接口 ,服务端是通过什么知道 带上来的 token 和 第一次生成的 token 一样的?

    我想了解的是这两个 , 谢谢
    algery
        16
    algery  
       2018-10-10 16:14:28 +08:00
    JWT 无状态; Session 有状态维护
    leafin
        17
    leafin  
       2018-10-10 16:31:46 +08:00
    @571726193 我觉得我已经讲清楚了。
    1.token 返回给客户端了,服务器不保存。
    2.没有什么第一个第二个的,服务器收到 token 的时候,能成功解密,就说明用户身份没问题。
    heimeil
        18
    heimeil  
       2018-10-10 16:40:14 +08:00   ❤️ 1
    一个 jwt 是由 3 部分组成,用 . 连接起来 Header.Payload.Signature,主要是最后的签名起到认证的作用,服务端先用 Header 里面的算法对 Payload 进行带密码的签名,别人没密码就签不出来同样的结果,生成后发给客户端,客户端再发给的服务端时,服务端再重复一下之前的签名操作,比对签名是否一致,相同就代表 token 没有被篡改。

    就像比较两个 md5 一样,只不过 jwt 是带了密码的,不然谁都可以伪造,签名正确的话 Payload 的内容就是可信的了。

    改密码之类强制清理用户 token 问题还需要一个黑名单系统,block 用户一个时间点之前的 token。
    chaleaochexist
        19
    chaleaochexist  
    OP
       2018-10-10 16:47:03 +08:00
    @heimeil 大神,数你说的最简单,而且说得通.

    > 改密码之类强制清理用户 token 问题还需要一个黑名单系统,block 用户一个时间点之前的 token。
    这个部分就需要用到数据库了对吧?
    譬如把过期的或无效的 token 放到数据库里面.
    lichao
        20
    lichao  
       2018-10-10 16:48:45 +08:00
    JWT 不能针对单个用户进行重置?
    heimeil
        21
    heimeil  
       2018-10-10 17:11:02 +08:00
    @chaleaochexist 不用存 token 的,只用存时间点就行了,对应用户 id,最好存在内存或 redis 里,过了你 token 配置的过期时间的那个窗口清理掉就行了,没必要一直存着每次都验证一次,这样资源相对节省一点。

    这样其实也不是太科学把,应该还可以探索更好的方法的。
    sobigfish
        22
    sobigfish  
       2018-10-10 17:15:07 +08:00
    xiaoxinshiwo
        23
    xiaoxinshiwo  
       2018-10-10 17:23:21 +08:00
    一个无状态,一个有状态
    mokeychan
        24
    mokeychan  
       2018-10-10 17:34:22 +08:00
    我理解 JWT 是一种规范,本身是一种生成 token 的机制。
    ZSeptember
        25
    ZSeptember  
       2018-10-10 17:36:57 +08:00
    说是两个概念的明显不理解到底是 session。
    leafiy
        26
    leafiy  
       2018-10-10 18:02:18 +08:00
    @571726193

    1. 客户端 token 存在 localstorage 或者 cookies 随意

    2. jwt token 本身包含过期时间和认证信息和用户 ID,服务端验证时需要解密,解密通过就是已登录用户,不通过就是未登录,逻辑非常简单

    !永!远!不!要!在服务端存储任何 token,包括 redis,真的!没!有!必!要!
    除非解码加密运算影响到你服务器性能了

    一个最简单的 express 的例子,客户端通过 headers 或其他各种方式,每次访问时都携带,服务端接收后解一下
    secrets 是定好的,不要泄露

    let decoded = jwt.verify(token, secrets);
    // decoded 失败直接 401 啊

    let userId = decoded.id;
    let exp = decoded.exp;
    // token 过期了
    if (exp < now) {
    return res.status(401).send({ reason: 'tokenExpired' });
    }
    // 验证 userId 是不是存在
    省略*****

    // 生成新的 token 发回去
    签发新的 token ****
    res.status(200).send({
    token: newToken
    })

    或者用 expressJwt 直接集成到 router 中

    expressJwt({ secret: secrets, credentialsRequired: true })
    precisi0nux
        27
    precisi0nux  
       2018-10-10 18:13:10 +08:00 via iPhone
    @crab 这个还是不是 100%靠谱,改密码只是个例子。时间戳没办法保证一改密码就让 token 失效。
    WordTian
        28
    WordTian  
       2018-10-10 18:16:12 +08:00 via Android
    jwt 信息存客户端,session 信息存服务器
    meik2333
        29
    meik2333  
       2018-10-10 18:18:07 +08:00
    对每个用户添加一个额外的参数一起加密解密,服务器端可以修改这个参数来使 token 立即失效。

    django 的 jwt 库我记得可以自定义用户的加密解密函数,把加密后的密码一块加入参数就可以保证修改密码 token 立即失效了。
    momocraft
        30
    momocraft  
       2018-10-10 18:18:52 +08:00
    session 是目标(请求关联到实体,多次请求关联到相同实体)

    如何传输( cookie 或别的 header,甚至 url 或 body ),内容是什么( key 或实体本身)都是实现细节,包括 JWT
    tachikomachann
        31
    tachikomachann  
       2018-10-10 18:31:03 +08:00 via Android
    @crab jwt 是有过期时间,但是只依赖 client 的 jwt 校验,无法做到让会话提前失效。
    tachikomachann
        32
    tachikomachann  
       2018-10-10 18:34:47 +08:00 via Android
    @precisi0nux 下面有朋友提到了,就是维护一个失效的 jwt 列表,当然这样就要服务端参与了。
    rainonline
        33
    rainonline  
       2018-10-10 18:55:44 +08:00
    @571726193
    1,JWT 生成 Token 的过程通常发生在用户登录的时候。在生成 Token 后随用户请求返回给用户,并储存在用户浏览器的 cookie 中。
    2,在 JWT 的规范里,服务器在校验 Token 的时候是不需要进行任何比对的。而仅仅通过算法就能计算出该 Token 是否有效。
    precisi0nux
        34
    precisi0nux  
       2018-10-10 21:10:01 +08:00 via iPhone
    @tachikomachann 那这不就不是 stateless 了么?
    dorentus
        35
    dorentus  
       2018-10-10 23:07:01 +08:00 via iPhone
    rails 的 session 也可以不存服务器啊,实现细节而已。
    gsw945
        36
    gsw945  
       2018-10-10 23:52:28 +08:00   ❤️ 2
    通常所指的 session,是和 cookie 配对使用的,session 是锁(保存在服务器端),cookie 是钥匙( session-id,存放在客户端,一般是浏览器);客户端发送请求时,查找 session 是否存在(有没有带钥匙?携带的钥匙能否打开锁?)。

    而 jwt,类似于一个机关锁,服务器端(可能是分布式,多台服务器)不存储内容,但是记录了开启密码锁的方法;客户端发送请求时,jwt 回传到服务器,尝试用记录的方法去解开机关锁,如果能解开,说明是有效的。

    如上 v 友所言,jwt 一般是通过设置过期时间来废弃,但是如果想废弃某一条 token,就需要借助存储手段;但是一般并不是存储完整的 jwt,而是记录 jwt 中的关键信息(比如用户 id ),放入黑名单,就算 jwt 解密成功,但是得到的关键信息在黑名单中,也可以拒绝。

    而 session/cookie 方式,session 是存在服务器端的,我把锁销毁了,就算你拿着钥匙来了,找不到能开的锁,也是没用的。
    (个人理解,仅供参考)
    xiaoshenke
        37
    xiaoshenke  
       2018-10-11 00:45:03 +08:00 via Android
    首先你要知道什么是 session session 解决了什么问题。简单来说 session 就是会话,http 协议是短链接是没有会话的概念的,就是说 http 协议干的事情就是一个请求过来返回一个结果回去。但现实生活中,比如我和你交流,我其实想记一下你是谁,下次我和你说话我就知道是你了,这也是 session 会话的意思。因此 session 是一个场景一个目标,jwt 是完成这件事的其中一个实现。
    cgpiao
        38
    cgpiao  
       2018-10-11 02:42:06 +08:00 via iPhone
    你既然数据库里保存 token 了,那 jwt 和 session 还有什么区别。你根本上理解错了 jwt。
    wenzhoou
        39
    wenzhoou  
       2018-10-11 07:03:36 +08:00 via Android
    补充一下。cookie 是浏览器的默认行为。如果你开发的不是网页,是 app,或者将来有可能开发 app,而不想搞两套的话,那就选 jwt。
    kran
        40
    kran  
       2018-10-11 07:12:11 +08:00 via Android
    没人规定 session 存服务器。
    robinlovemaggie
        41
    robinlovemaggie  
       2018-10-11 08:16:59 +08:00 via Android
    一个追求效率,一个追求安全。一个面向算法安全,一个面向存储安全。各有优劣,合理取舍。
    caotian
        43
    caotian  
       2018-10-11 09:30:11 +08:00
    @precisi0nux 用每个用户的密码作为加密 key 给用户生成 token 如何? 这样用户改了密码之前的 token 全部失效, 会不会有性能问题?
    zhaogaz
        44
    zhaogaz  
       2018-10-11 10:39:27 +08:00
    区别当然有

    session 是会话。它指的是服务端保存的交互状态,就是记录哪些人正在访问我们的网站。java servlet 是通过 jsessionid 的这条 cookie 来追踪的,每次交互的时候,servlet 容器会通过这个 cookie 来识别是哪个 session

    jwt 全名叫 json web token。一般是每次 http 请求的时候携带的票据,我记得是 oauth 2.0 协议里面的东西。每次 http 请求的时候携带在 header 中。

    这两个东西根本就不是并列的,不知道怎么就误会到一起了。其实还挺奇怪的是还有很多人不清楚 cookie 和 session (顺便吐个槽
    EchosKK
        45
    EchosKK  
       2018-10-11 10:57:40 +08:00
    @caotian 我刚也想到这个,但是会有个问题,解密的时候,用户密码从哪儿来?
    dallaslu
        46
    dallaslu  
       2018-10-11 11:14:27 +08:00   ❤️ 1
    1. 假期出游,你开车经过检查站,交警拦住了你,检查的驾驶证,性别、年龄、过期时间、防伪标志都没问题,大手一挥,放行了。

    2. 离服务站两公里的应急车道上,一个妹子气鼓鼓的踢了几脚她的车子。坐在你副驾上的基友还是单身,给了你一个眼色,你马上把他放下去搭讪。原来妹子的车总是熄火,基友提出帮忙开到服务站。面对妹子不确认的眼神,基友掏出了驾驶证,性别、年龄、过期时间、防伪标志都没问题,妹子果然不再怀疑:果真是个老司机呢!

    3. 一路风尘仆仆,你和基友去绿色洗浴城放松。你觉得有点热,喊服务生拿两听可乐,服务生过来看了一眼你的手牌号:777。你基友觉得有点燥热,喊服务生叫两个技师,服务生过来看了一眼他的手牌号:888。结帐时候果然算得分毫不差。

    4. 柜台前随手刷了一下朋友圈,一个发小在晒手牌号:绿色洗浴城 666。你跟收银说,666 号的单我买了。收银员说:今天没有 666 号的客人啊,你朋友可能是在其他连锁店里吧。

    基友坐在车里发着呆,若有所思。你打趣道:想白天那个妹子呢,还是回味刚才呢?你不会是想着工作的事儿吧?

    基友不紧不慢的说:我琢磨着,驾驶证有点像 JWT,过期之前哪都能用,信息都在证上明写着;手牌有点像 SESSION,只能在店里用,消费都记在收银系统里。

    你皮笑肉不笑的斜了他一眼,心里骂道:神经病。
    Ravenddd
        47
    Ravenddd  
       2018-10-11 11:31:28 +08:00
    我认为两个可以一起用, 各司其职
    session 控制用户的各个状态都很好, 服务端控制很灵活;
    JWT 的特点就是无状态偏向与安全认证授权之类的;

    之前我也想用 jwt 代替 session, 可是最后发现状态控制如果加上黑名单之类的就变成 session 了, 不知道还有什么应用场景, 知道的大佬请说一下
    wizardoz
        48
    wizardoz  
       2018-10-11 13:05:09 +08:00   ❤️ 1
    jwt 是一个认证凭证,从某种意义上说它和 username+password 是对等的。
    session_id 是一个会话标识,服务器记录了一次业务的中间状态,当然如果认证状态为“ authenticated ”的话,看起来作用好像和 jwt 一样,但其实不是一样。就算没有用户认证的需要,也可能需要 session 来完成业务。

    另:jwt 可以不在服务器上保存任何东西,因为 jwt 是可以用 RSA 签名实现合法性验证。
    caotian
        49
    caotian  
       2018-10-11 14:15:50 +08:00
    @EchosKK jwt token 不是加密的,里面的 payload 都是明文的, 只是最后一段是 hash 值, 用来判断 token 是否有效。 所以 payload 内容是可以直接读取出来的, 比如如果有 uid 读取出来了, 程序里可以查出来用户密码 hash 什么的, 再进行 jwt hash 判断
    yulitian888
        50
    yulitian888  
       2018-10-11 14:20:44 +08:00
    这个问题直接去看 JWT 官网不就好了吗?

    简单来说,两者不具备可比性,因为适用场合不同。传统 Web 应用更合适 Session,因为操作是连续的。而 App 等新型网络程序往往需要登录一次管半年,而且是“偶尔”连接,对吧!这就是 JWT 适用场合了呗!
    zhzer
        51
    zhzer  
       2018-10-11 14:28:46 +08:00
    简单说 jwt 就是带有前端通信功能(能被前端抓)的 session

    jwt 的需求是建立在前后端分离,前后端需要同步用户信息上创建的
    由于各种后台框架很繁杂,也就没有特别的 jwt 标准,其实简单修改 session 就能达到 jwt 所需求的效果
    ZhengJL
        52
    ZhengJL  
       2018-10-11 14:32:33 +08:00
    通俗一点的说 JWT 相当于一把加密后的锁,用户登录服务器把锁给到客户端,客户端每次请求都必须带上,请求到达服务器如果服务器端可以用钥匙解开,并且锁内容没有过期,就说明用户是登录的,如果打不开或者打开后发现过期了,证明登录失效
    qile11
        53
    qile11  
       2018-10-12 00:34:43 +08:00 via Android
    @ZhengJL
    同意一些,jwt 应该是为了保证客户端与服务器通讯安全而产生的,过期时间和密码是保证安全的方式,可以不设置过期时间,解密后可以通过用户名验证用户的合法性,也可以将一些数据加密传输(有些接口会使用 jwt 加密传输接口数据)。
    session 应该是一种服务器应用,保持回话并存储一些数据,一般保存与服务器,cookie 保存与客户端。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5276 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 08:05 · PVG 16:05 · LAX 00:05 · JFK 03:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.