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

使用 token 不是还是要每次都需要从数据库加载用户信息么和传统 session 有什么区别?

  •  1
     
  •   SystemLight ·
    SystemLight · 2021-09-13 08:33:40 +08:00 · 8070 次点击
    这是一个创建于 927 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • 使用 token,由于 token 存储的是少量信息,是不是每次都还需要在拦截器中验证并去数据库加载用户信息
    • 如果一个前端页面包含多个请求,每个请求都需要鉴权数据库压力不是很大么
    • 解决是不是可以用 redis 集群做信息缓存,但是这样和传统 session 操作方式不是类似么
    • 所以说 token 和传统 session 优势是什么,token 概念上是无状态,但是不可能真的把用户所有信息都存上呀
    48 条回复    2021-09-20 21:22:01 +08:00
    xuanbg
        1
    xuanbg  
       2021-09-13 08:43:54 +08:00
    没区别,楼主继续用 session 就行。反正无状态的 token 适用范围有限,需要鉴权的时候,token 也要改成有状态的才行。
    lcy630409
        2
    lcy630409  
       2021-09-13 08:45:23 +08:00   ❤️ 4
    个人理解
    token 可以节约后端的兼容时间,用 token 代替 session 可以做到 网页、app 、微信公众号等公用一套接口即可。
    还不用考虑用户浏览器是否禁 cookie 了。

    token 看项目,大部分项目就是简单的把 token 当成 session 的另版,少部分是把 token 当做信息传输
    THESDZ
        3
    THESDZ  
       2021-09-13 08:51:02 +08:00
    个人见解:

    要看 session 这个概念

    如果是说之前的实现方式,那就是有状态的,跟随服务节点的,不利于多服务,多节点的场景.

    而如果说是为了保存用户信息这一目的,或者行为,那 token 可以理解为新的实现方式.
    skypyb
        4
    skypyb  
       2021-09-13 08:53:31 +08:00   ❤️ 9
    token 是令牌的意思, 这个明白吧。
    web 领域中的 session 也是一个用户的令牌, 这个没问题吧。

    so, 我寻思 session 不就是 token 么(一种实现)? 没看懂在讨论什么

    如果说的是 JWT (json web token)这种实现方式,这个确实是无状态的。
    当你见到有人用 JWT 的同时, 还通过这个 JWT 去查库 /查缓存从而获取信息, 那么你应该判定这个人是个傻逼。
    chendy
        5
    chendy  
       2021-09-13 08:56:03 +08:00
    其实 sessionId 就是一种 token,只是通过 token 获取 session 数据 的操作由 web 框架做,而且一般将 sessionId 保存在 cookie 里,session 数据保存在 web server 里
    因为 session 保存在 web server 里,当有多个实例时,需要同步各节点的 session,或者把 session 保存在数据库里(比如 spring-session )
    因为 sessoinId 保存在 cookie 里,所以当客户端不支持 cookie 机制时,这套东西就没法用了
    也因为 sessionId 保存在 cookie 里,所以可以使用浏览器自己的安全机制,比如 http-only,same-site 等
    还是因为 cookie,所以对于前端是透明的,不需要自己管理,发请求默认带着(可能有跨域问题)

    > 如果一个前端页面包含多个请求,每个请求都需要鉴权数据库压力不是很大么
    相当于每次请求多一次查询,必然走索引,压力不大

    > 解决是不是可以用 redis 集群做信息缓存,但是这样和传统 session 操作方式不是类似么
    用 redis 可以提高性能,还自带过期时间机制,emm,本来就是 token 拿 session,就是一样的,区别是谁做怎么做

    > 所以说 token 和传统 session 优势是什么,token 概念上是无状态,但是不可能真的把用户所有信息都存上呀
    可以在浏览器之外的环境使用,而且因为全部自己实现,一些操作更方便(比如检测 token 状态,废掉某些 token ),用 JWT 可以在 token 里带数据,但也会带来额外的复杂性,需要自行评估使用
    chanchan
        6
    chanchan  
       2021-09-13 09:00:07 +08:00
    我觉得
    session 就是服务端查内存中是否有对应 session 来区分客户端
    token 就是服务端解密看 token 里面内容来区分客户端
    jorneyr
        7
    jorneyr  
       2021-09-13 09:08:19 +08:00
    本质上没什么区别,为了支持多端用户的请求有的 token 实现简单点,例如 90% 的需求使用 JWT 存储用户基本不变的信息就能够满足,不需要服务器间同步 session 信息 (集群模式下高并发时同步 session 的性能损耗不可忽视,而 token 一般不需要),有需要的时候再回查用户信息。
    huijiewei
        8
    huijiewei  
       2021-09-13 09:11:13 +08:00
    session 有并发限制
    tedzhou1221
        9
    tedzhou1221  
       2021-09-13 09:11:51 +08:00
    JWT 的登出,或者刷新新的 Token 的处理,废弃旧的 Token

    这两个功能是需要有状态的。

    如果还有更好的处理方式,各位大佬可以告诉我一声,我正在做这个功能。感谢
    ospider
        10
    ospider  
       2021-09-13 09:12:51 +08:00
    你这都是书本上的定义,这么说的话 Cookie 和 Session 也分不开。实际使用中的 Cookie,Session,Token 区别大概是:

    - Cookie:在浏览器的 CookieJar 中存储信息,比如购物车等,每次 HTTP 请求强制携带;
    - Session:通过存储在 CookieJar 中的小段信息作为 Token,在服务器中加载相关完整信息;
    - Token:通过存储在浏览器 localStorage 中加密签名过的 Token (一般是 JWT ),在 HTTP Authorization Header 中可选发送,并在服务器汇总加载相关完整信息。
    murmur
        11
    murmur  
       2021-09-13 09:12:53 +08:00
    jwt token 长度必定是有限的,如果用户的数据复杂了,token 就存不下了

    如果你就是 uid 和中文名,那 jwt token 是勾的
    golangLover
        12
    golangLover  
       2021-09-13 09:17:59 +08:00 via Android
    @tedzhou1221 #9 你不如去 4 楼问问说有状态 jwt 是 sb 的人 @tedzhou1221 #9
    quanqiubiannuan
        13
    quanqiubiannuan  
       2021-09-13 09:21:26 +08:00
    为什么要拿 token 和 session 来比?
    fkdog
        14
    fkdog  
       2021-09-13 09:22:58 +08:00
    token 和 web session 本身就是同一个东西, 区别只在于生命周期和存储位置不一样.
    huang119412
        15
    huang119412  
       2021-09-13 09:25:27 +08:00
    http 中的 session 和 cookie 关联在一起的,由 web server 自动维护,不需要用户操作,所以 session 并不灵活。
    pastgift
        16
    pastgift  
       2021-09-13 09:31:23 +08:00   ❤️ 6
    Session 一般指的是,通过在 Cookies 里保存的一个 SessionID 实现鉴别用户的处理方式
    好处是对 Web 前端,也就是浏览器基本上是透明的,前端开发不用管

    Token 一般指的是,登录成功后,通过 JWT 等方式把少量信息编码成一串字符串返回给客户端,客户端在请求时一般将其附带在 HTTP Header 上,供服务端鉴别用户的处理方式
    好处是任何客户端都能方便处理,并且 JWT 方式客户端本身也能获取字段信息

    > 使用 token,由于 token 存储的是少量信息,是不是每次都还需要在拦截器中验证并去数据库加载用户信息
    > 如果一个前端页面包含多个请求,每个请求都需要鉴权数据库压力不是很大么
    > 解决是不是可以用 redis 集群做信息缓存,但是这样和传统 session 操作方式不是类似么

    是这样的,如果 Token 中保存的信息少到只有 Token ID,那和传统 Session 的唯一差别就在于是不是依赖 Cookies 了

    > 所以说 token 和传统 session 优势是什么,token 概念上是无状态,但是不可能真的把用户所有信息都存上呀

    没有必要严格按照概念、范式,要面对实际问题

    我实践下来的感受是有状态的 Token 比严格的无状态 Token 更好用,主要还是用在服务器端作废 Token,用户权限变更需要及时生效之类的处理上。

    此外,Token 附带的信息并不限定「用户信息」

    比如,要实现客户端发生变化( IP 、UserAgent 等)后,强制退出的功能,可以在 Token 发行时将客户端相关信息 MD5 后加入 Token,后续收到 Token 之后拿 Token 中附带的客户端信息 MD5 值和本次请求实际的客户端信息 MD5 值进行比对,有变化就拒绝,从而加强一定安全性,且操作完全不经过数据库、Redis 等其他组件。

    再比如,要实现服务器端升级后,要求所有用户重新登录(重新发行 Token ),那么同理,发行时把服务器端的版本号写入 Token,收到 Token 时进行比对,这同样不需要额外查询数据库、Redis 。

    也可以实现按照业务的请求转发。
    比如 VIP 用户可以在 Token 中写入 VIP 标记,那 API 网关就可以将此请求转发到不同的服务器 /集群上处理,也能避免 API 网关去直接去数据库查询业务数据。

    其他的那种比较直观的,比如展示在页面上的用户昵称如果写入 Token,那前端可能就可以不用额外请求用户信息接口。但这些都不太重要
    jiangboenoch
        17
    jiangboenoch  
       2021-09-13 09:39:35 +08:00
    @skypyb #4 最近在学后台,如果不往 token 放状态,那做 token 过期和自动续期应该用什么方案呢?
    MLeo
        18
    MLeo  
       2021-09-13 09:44:10 +08:00
    简述 Cookie 、Token 、JWT 、Session
    https://ichochy.com/posts/20200825.html
    liyunyang
        19
    liyunyang  
       2021-09-13 09:44:41 +08:00
    @pastgift 学习了
    skypyb
        20
    skypyb  
       2021-09-13 09:58:49 +08:00   ❤️ 1
    @jiangboenoch #37
    当 Token 需要例如过期、自动续期这种功能时, 那他就应该是一个有状态的 token, 典型的比如用户登陆后标识此用户的令牌。
    每个请求都根据 Token 去查库就行了,比如查 Redis 。
    如果在 web 端使用的话放不放 Cookie 里随便,只是不放 Cookie 的话里就自己控制刷新咯。

    像那种无状态的,也就是完全不经过 DB 那一层的,比如 JWT 这种。
    他压根就不适合做用户令牌这种场景,也不知道是不是什么培训班灌输的思想钢印。
    最适合 JWT 的场景是那种需要短时间获取权限的行为,比如 XX 时间内有效的下载、查看等这种接口。

    硬是要用 JWT 来当用户令牌的话,那为了查这个令牌有没有被吊销掉,还是得每个接口都去查一次库。那你反正得查库,为啥不顺便查出用户信息?

    所以说,如果只是用作用户标志的话, 那就是直接用一个全局不重复的字符串来当 token 就行了,每次请求查一次库。

    最后再说一下。session 是会话,web 端的 token 就是这个会话的令牌, 无论是叫他 sessionId 也好,叫他 xxx-token 也罢,他都是一个东西。和他放在 Cookie 里还是 localStore 里没有任何关联。
    skypyb
        21
    skypyb  
       2021-09-13 10:07:03 +08:00
    @skypyb #20, 这里上边场景说错了,应该是手动吊销,风控自动下线,权限更改等场景。
    如果只是单纯的过期实际上你用啥都行,JWT 里就能存失效时间。用户令牌很明显是不可能只有单纯过期这种场景的。
    aoling
        22
    aoling  
       2021-09-13 10:13:19 +08:00
    JWT 建议还是在服务端带一个状态,特殊情况可以作废 token,不然你只能等待 JWT 的规定过期时间
    aboat365
        23
    aboat365  
       2021-09-13 10:35:28 +08:00
    forbreak
        24
    forbreak  
       2021-09-13 10:35:44 +08:00
    本来做的就是一件事,肯定没区别。 但是各种场景适用一下 token 就有优势了, 举例: 分布式场景,如果是传统 session,你还要做 session 共享,麻烦还不太可控。用 token 你本来就是自己去缓存或者库去查询的。也就不存在这个问题。 还有就是:多端使用的时候、作为接口使用时候,各种魔改的情况等等还有很多情况下,如果用 token 魔改起来比较方便,毕竟自己实现的。你还可以做成有状态。各种骚操作,改起来方便很多。
    crayygy
        25
    crayygy  
       2021-09-13 10:37:41 +08:00
    可以了解一下 SSO 和 OAuth2,在这种情况下的区别就很大了。
    hst001
        26
    hst001  
       2021-09-13 10:39:08 +08:00 via Android
    什么 token session jwt 都是等价的一套机制,没有哪个功能是各方实现不了,用哪个都是一样的,非要选一个,那就看个人或团队偏好
    ytmsdy
        27
    ytmsdy  
       2021-09-13 11:16:10 +08:00
    session 其实算是一种特殊的 token,本地也是有一个叫 SessionId 的信息来标识具体是那个用户的。
    lap510200
        28
    lap510200  
       2021-09-13 11:44:48 +08:00
    因为纯无状态的不好搞单点和 token 主动失效,但是兼容性好,app,h5,各平台小程序用一套,session 不行
    cyaki
        29
    cyaki  
       2021-09-13 11:56:49 +08:00
    bowser1701
        30
    bowser1701  
       2021-09-13 15:00:49 +08:00
    @crayygy OAuth2 等鉴权方式与这里讨论的储存 session 方式是没有关系的,用 OAuth2 鉴权还是需要考虑这里讨论的 session 存储的。
    ksc010
        31
    ksc010  
       2021-09-13 15:22:06 +08:00
    你说的 session 应该指的是 sessionid,sessionid 的载体可以有多重
    比如放到 cookie,http 头, 或者 url 参数中
    一般说的 token 也是一种 sessionid, 会放到 http 头 或者 url 参数汇总

    后端根据此“sessionid” 识别具体 session (会话)
    cjc2017
        32
    cjc2017  
       2021-09-13 15:32:43 +08:00
    @cyaki 好一个取水用水
    kingfalse
        33
    kingfalse  
       2021-09-13 18:08:30 +08:00 via Android
    说白了,就是 session ID 放在 cookie 头还是别的头的问题
    qianji201712
        34
    qianji201712  
       2021-09-13 18:13:34 +08:00
    其实从目的上来说,都是同一类东西,无非是用于用户合法校验,只不过实现机制不一样罢了,Token 适用性更强,web,app,pc 都可以一套。
    至于所说的频繁查询,肯定要做一些优化的(不然每次操作都要去 db 查一遍,没必要这么浪费性能),扔 redis 吧,简单快捷。
    p786317875
        35
    p786317875  
       2021-09-13 18:13:35 +08:00
    只能说:Token 可以强化成 Session 的形状,Session 无法退化成 Token 的形状
    markgor
        36
    markgor  
       2021-09-13 20:47:02 +08:00
    我自己的理解,

    无状态 token 一般都是根据具体权限进行加密生成出来,接收到的时候解密验证权限,不存在加载用户信息。
    比如登陆后的读写操作。
    生成 token:md5 ( uid +md5 ( 1+1 ))
    前端提交:token,uid (明文)
    后台验证:
    可读:md5(uid+md5(1)) || md5(uid+md5(2))
    读写:md5(uid+md5(2))
    *日志要记录就用 uid 就行了。

    实际上生成规则还需要加入随机数等的,都是生成时候后端传给前端,后续前端都需要携带这些服务端才能验证,作用时防止被猜到验证规则。

    然后还有一种 jwt,
    这种直接把参数放入载荷里,传给前端,由于解密需要 key,所以前端是没法解密的,但是后端只需要获取到 jwt 就能解密出来。
    一般情况下,你把用户 id,昵称,性别,头像,权限这些丢进去载体,
    后端解密后就能直接用了,不存在查数据库。
    jwt 加密方式是根据这些参数进行加密的,所以如果前端改了这些参数,加密的结果就会不一样,除非把 key 给碰撞出来了。
    *很多文档都说不要把私密信息放载体,但我觉得如果对方能解密出来,那载体放什么已经不重要了。

    最后,由于是无状态,那么踢出用户 或限制 不能多端登录类的无法实现,这时候可以配合 redis 做个黑名单功能,后端验证 jwt 前都查一次是否存在 redis 黑名单里,存在里面的就直接返回失败。
    jimrok
        37
    jimrok  
       2021-09-13 21:15:04 +08:00
    session 通常在 java 的应用上搞,token 可以跨越多个应用,甚至可以传递进 mq 里鉴权。
    jimrok
        38
    jimrok  
       2021-09-13 21:20:25 +08:00
    session 通常是一个登录状态的维护,tcp 的长连接维持,也可以用 cookie 来追踪。token 可以替代密码鉴权来创建 session,所以 token 通常是为了鉴权用,而 session 是为了维护鉴权后的状态。
    wunonglin
        39
    wunonglin  
       2021-09-13 21:31:17 +08:00   ❤️ 1
    jwt token != token!!!
    jwt token != token!!!
    jwt token != token!!!

    要说多少次啊。唉
    mmdsun
        40
    mmdsun  
       2021-09-13 23:18:12 +08:00
    @skypyb jwt 要实现服务端强制下线的功能的话,就要服务端存状态了
    2i2Re2PLMaDnghL
        41
    2i2Re2PLMaDnghL  
       2021-09-14 02:19:53 +08:00
    传统的 session id 是任何能写入数据库的人可以写入 session data,任何能读取数据库的人可以读取 session data,数据实际存储在一个中心化的设施上。
    JWT 则是所有拿到密钥的人都可以写入或读取 JWT payload,数据实际存储在客户端。
    Quarter
        42
    Quarter  
       2021-09-14 09:06:38 +08:00 via iPhone
    token 其实就是 session 另一种形式,之前通过在 cookie 里面设置一个 id,然后通过 cookie 中的 id 在 session 里面查询缓存数据,token 功能也是如此,但是 token 不局限于 cookie 存储,可以使用 localStorage 等前端存储使用,另外 token 也可以衍生加入用户信息或者其他关键信息( jwt ),这样可以从 token 中获取到一些用户信息,这就是我理解的他们之间的联系

    至于数据读取问题,你提出的问题确实存在,我们还是要从缓存甚至数据库读取更多的用户信息,但是 token 的好处在于可以方便统一认证或者跨站认证,我们可以携带 token 去访问另一个服务,同时携带了 token 信息直接免除了登录,而 cookie 就不那么方便了,一般为了安全性我们也不让 js 读取 token
    ihipop
        43
    ihipop  
       2021-09-14 10:48:00 +08:00 via Android
    @skypyb jwt 存所有业务内容?业务内容算不算信息?通过 jwt 获取业务内容的都是伞兵?
    summerLast
        44
    summerLast  
       2021-09-14 10:58:26 +08:00
    这个问题可以拆解成 3 部分
    1 token 和 session 相同处是什么
    因为 http 是一个无状态的协议 但很多场景需要状态 token 和 session 本质都是令牌或凭证
    2 token 和 session 区别是什么
    session 是 token 的一种实现 此处我们谈 token 的时候可以换成 JWT Token 和 session 去做对比,那 JWT Token 和 session 区别是什么呢? JWT 全称 JSON Web Token 也就是说是 JSON 格式的 Web 令牌,session 或 JWT Token 都是一个存放信息的容器,关键在于状态( C/S )谁来保持,及什么样的信息放在哪是服务器还是客户端更合适,放服务器优势是什么劣势是什么,放客户端优势是什么劣势是什么(可以参考计算机缓存内存硬盘的架构)
    3 各自优势是否可结合
    在一个应用多实例或前后端分离的情况下,不易变的信息放 JWT Token 相对更合适;不需要考虑这种情况下,放 session 更合适, 或者换句话说 让 Token 只做一个凭证就是一个身份证的事情,后面的映射交给后端
    题外话:
    其实就像为什么了有了硬盘还需要内存 有了内存还需要 CPU 缓存 ,结合各自的优势让问题得到更好的解决是目前比较好的方案,而不是非此即彼
    summerLast
        45
    summerLast  
       2021-09-14 11:08:37 +08:00
    此处不应该拿 session 和 token 对别 ,而是应该拿 cookie-session 中的 sessionId 和 jwt token 对别
    ptrees
        46
    ptrees  
       2021-09-14 11:38:38 +08:00
    我用 jwt 就只是存 userid,其他的还得去数据库取,这种用法不对吗?
    fatttt
        47
    fatttt  
       2021-09-14 17:23:43 +08:00
    @skypyb jwt 容量有限。比如有用户权限信息的时候,就不够了。只能存个 id,然后查库缓存。
    fengpan567
        48
    fengpan567  
       2021-09-20 21:22:01 +08:00
    token 和 session id 性质一样,对于集群环境,session 需要用组件打通各个节点服务的 session 数据来保证每个节点可以识别出用户,token 则是自己手动去查库或者 redis,还是 token 更灵活一点
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5534 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 09:04 · PVG 17:04 · LAX 02:04 · JFK 05:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.