最近在细读 REST 那篇论文, HTTP 的设计应该就是来自于这里
看到了 无状态 这里, 有一点小疑问: 为什么 session 机制没有被 JWT 所取代?
session 毫无疑问是不符合无状态的, 它使得会话状态(session state)保存在了服务器中. 产生的问题也很清晰: 由于会话状态保存在了服务器, 所以需要多个服务器间同步会话状态
JWT 就是将会话状态存在了客户端(cookie), 服务器端需要的时候自然会解析验证. 也没有多服务器间的同步麻烦.
但是, 现状却是大多网站都是 session 的机制, JWT 只有小部分的 WEB API 使用.
我的标题可能起的有些问题, 我想请教的是 Session ID & JWT
会话状态(session)在交互型的网站是无法避免的, 但是 Session ID 在之前我看来是可以避免的
在我的理解里
Session ID 是使用随机字符串, 会话状态内容是保存在服务器端的
而 JWT 的本质是校验, 他得到的会话状态完全来自于客户端, 没有存储在服务器, 这在我看来完全是符合无状态架构的.
至于说过期, 注销等问题也有想过一些解决方案.
不过, 经过讨论和V友们的指点, 我也明白了:
每次请求的内容过多是无状态的缺点, 但是这个缺点也不应该无限制的放大, cookie 的4096字节的限制应该就是做出的这种限制.
那一旦 jwt 所需要存储的内容超过了某个阈值, 它的某些内容需要使用 ID 等标识, 其实与 Session ID 就没有太大的区别了.
虽然之前我一厢情愿的想着 jwt 中的 id 代表资源标识, 但是其实本质上没有区别.
so, 这其实是一个比重取舍的问题, 会话状态需要存储的东西越多, 越不应该使用 jwt , 因为 jwt 要比 Session ID这个随机字符串大多了
万分感谢V友的热心指点!!!
同时希望这些内容对收藏的朋友有所帮助
1
k9982874 2017-08-10 18:07:42 +08:00 via iPhone 1
jwt 本质也是 session
|
2
baiyi OP |
3
bazingaterry 2017-08-10 18:14:11 +08:00 via iPhone 2
session 可以在服务端注销,而一般的 JWT 不可以。
|
4
baiyi OP @bazingaterry
这个我有想过,jwt 想要实现这个功能也是可以的,既然不能改变会话状态,可以改变会话中的资源状态,比如一般来说的用户,注销后可以修改资源状态,每次效验会话状态时,可以先查看资源状态 比如一般情况下的用户会话状态,注销后可以在服务器端同步一条用户资源的注销情况,验证会话时查看是否已注销 想的也没有太仔细,注销时间应该可以判断吧 |
5
syncher 2017-08-10 18:21:28 +08:00 via Android 1
JWT 怎么做延时?比如用户操作 30 分钟 token 失效这个功能 JWT 实现不了
|
6
syncher 2017-08-10 18:22:52 +08:00 via Android 1
#5 用户无操作 30 分钟 token 失效(手欠)
|
12
baiyi OP @syncher 为什么呢?很麻烦吗,如果是存储在 cookie 中,甚至前端完全不需要处理的。app 一般不需要时效性,app 用的都是刷新机制
|
14
littleylv 2017-08-10 18:44:49 +08:00 1
JWT 用在 API 中挺好的,但用在正常的客户操作上感觉会多出好多麻烦的事(我没用过),为啥不直接 seesion 解决呢
|
15
baiyi OP |
16
baiyi OP |
17
carlclone 2017-08-10 18:53:14 +08:00 via Android 2
session 和 cookie 不是为了解决 Http 无状态才产生的吗。。。怎么会符合无状态?
|
18
baiyi OP @carlclone 哎? cookie 也是解决无状态的吗?我认为将数据存在客户端是符合无状态的
|
19
carlclone 2017-08-10 19:01:21 +08:00 via Android 1
@baiyi 哎我感觉你要补充一下 HTTP 的基础吧,session 就是 cookie 的升级版
|
20
Mutoo 2017-08-10 19:04:22 +08:00 5
cookie 的问题在于不能跨域,session 存在 cookie 里符合早期的 c/s 一对多的服务方式,而如果业务需求增长的话,servers 需要横向扩展,这要求 session 必须能在多台 server 之间同步共享。jwt 简化了这个共享的过程,只要任一 server 持有 private key 能解密 jwt 就能获得关键的用户数据,而不必把 session 在多台 server 间存放。
|
21
baiyi OP @carlclone 抱歉,那我可能对 cookie 和 session 的理解有错误。不过,如果说是为了解决无状态出的方案,那就是说明无状态是有缺陷的。能给点提点吗
|
22
carlclone 2017-08-10 19:06:53 +08:00 via Android 1
客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。HTTP 本身是一个无状态的连接协议,为了支持客户端与服务器之间的交互,我们就需要通过不同的技术为交互存储状态,而这些不同的技术就是 Cookie 和 Session 了。
|
25
Mutoo 2017-08-10 19:11:20 +08:00 1
@baiyi 这不代表 session 就会被取代呀。用 cookie 维护 session 是在 web 应用中非常直接的用法,没必要用大炮打蚊子。不过慢慢的越来越多的新框架会支持 jwt,而且在很多非 web 场景,也可以使用 jwt。
|
26
WildCat 2017-08-10 19:12:16 +08:00 1
我现在用 django-rest-frameowork-jwt,感觉非常好 =。=
但是如果传统后端渲染项目我还是会选择 session,就是为了简单。 补充一句,貌似 Rails 的 session 默认 store 其实就是加密后的 cookies |
27
wellsc 2017-08-10 19:12:49 +08:00 1
我司在部分项目中已经用 jwt 取代 session 了。
|
28
Mutoo 2017-08-10 19:13:20 +08:00 1
@baiyi 无状态不是缺陷,相反是优势,这样才更有机会做均衡负载。但面对的问题就是如何在多 server 端维护同一 client 的状态,也就是 session。
|
29
baiyi OP @carlclone 原来是这段理解,这个我有看过,但并不认同,无状态不是不存在会话状态,而是不应该存储在服务器端。这是我对无状态的理解
|
30
baiyi OP |
32
baiyi OP @所有人 感谢回复,手机浏览器不知道怎么感谢,回家后再点
|
33
cxh116 2017-08-10 19:20:45 +08:00 2
http 协议有 session 吗? 没有.
session 不过是基于 cookies 的服务端会话保存方案而已. jwt 的 token ,相当于 cookies 的 session id.两种方案无本质区别. 比如 rails 的 session,就是把信息加密存到 cookies,每次请求都把 cookies 传过去,这样实现了你想要的无状态? |
34
carlclone 2017-08-10 19:20:54 +08:00 via Android 1
那你还是去看 RFC 吧 醉醉的
|
35
Event 2017-08-10 19:21:17 +08:00 1
见 YII2 框架 有 Cookie 验证机制
|
36
saberscarlet 2017-08-10 19:22:10 +08:00 via Android 1
我们这现在 web 项目用 redis 存 session,app 项目用 jwt
|
37
andyangyu 2017-08-10 19:23:46 +08:00 via Android 1
搭车问一个登录刷新活动状态的问题,我现在是每次请求通过 session 更新数据库,有其他更好的办法么?
|
38
baiyi OP @cxh116 对,会话状态存在客户端就是我认为的无状态,rails 的做法符合,但是我认为缺点是客户端无法获得会话状态,因为客户端是不能有加密的能力
|
40
baiyi OP 我见到的大部分框架都是通过加密存储,解密读取的方式利用 cookie,而 jwt 则是验证,客户端也可以查看会话状态,使用方向不同,我认为在鉴权方面 jwt 更好用
|
41
gamexg 2017-08-10 19:28:49 +08:00 1
尺寸,session 保存一个 id 即可,jwt 要求所有 session 都存放在 cookie,保存太多的东西小心炸。
|
42
baiyi OP @gamexg 嗯,这是个问题,cookie 据我检索到的资料是 4kb 的存储大小,所以,我只放入了少量权限方面无法替代的内容,例如用户 id,权限 id
|
43
baiyi OP 我觉得这里是问题的关键,我想再提出个问题,如果 jwt 不能包含所有内容,需要通过 id 等标示查找资源,那和 session 的区别呢……
|
44
kiddult 2017-08-10 19:41:25 +08:00 1
刚查了一下,JWT 本身就是 session 吧,只是蛋疼的用 JSON 来表示
|
46
tairan2006 2017-08-10 20:35:59 +08:00 1
session 只是一个概念。。
|
47
erobot 2017-08-10 20:40:48 +08:00 1
不是做 web 的,查了一下说一下理解。
http 协议设计是无状态的,业务如果要求会话的概念,那么需要用某种技术实现,通常都是基于 cookie 的。session_id 和 jwt 都是某种实现会话技术存储在客户端的数据而已,主要区别应该是在于格式和标准化程度,他们完全可以存储一样多的信息,如果空间没有限制的话。 按照我的理解,正常 jwt 里面也应该是有类似 session_id 一样的信息的,不然就是密码本身而不是 token 了,尤其是类似登录状态,服务端应该有能力回收客户端的授权。 关于客户端是否应该存储所有会话状态信息,rfc6265 里面有这样的说法: 8.4. Session Identifiers Instead of storing session information directly in a cookie (where it might be exposed to or replayed by an attacker), servers commonly store a nonce (or "session identifier") in a cookie. ... Using session identifier cookies limits the damage an attacker can cause if the attacker learns the contents of a cookie because the nonce is useful only for interacting with the server (unlike non-nonce cookie content, which might itself be sensitive). |
48
bazingaterry 2017-08-10 20:50:35 +08:00 via iPhone 1
JWT 好像就是把 session 签名后存在了 Cookies 里面?
|
49
loveCoding 2017-08-10 20:54:26 +08:00 2
@littleylv #14 一般的项目 ,随着需求越来越复杂 ,比如登录设备限制 , 自动踢下线 . 不是 session 最后慢慢都会变成 session 样子的.
|
50
yangff 2017-08-10 21:06:47 +08:00 1
……群魔乱舞
|
51
Infernalzero 2017-08-10 22:23:14 +08:00 1
session 的应用要广得多,存服务端通过 session 属性可以做很多事
|
52
huijiewei 2017-08-10 22:32:09 +08:00 via iPhone 1
session 是有锁的
|
53
sujin190 2017-08-10 22:44:12 +08:00 1
其实两者其实并没有什么区别
session 现在如果存在服务器大多也会使用 redis 这样分布式存储方式,不存在不能横向扩展的问题,再者 session 也并不是一定要保存在服务器,完全可以加密放到 cookie 里 jwt 也并不是没有问题,比如正常情况下要比 session_id 更大,需要消耗更多流量,挤占更多带宽,已经无法在服务端注销,那么久很难解决劫持问题 此外 jwt 一般只会直接保存用户 id 这样信息,那么正常情况下还是需要用户更多信息,那么同样需要 redis 这样高效率缓存系统配合,那么效率上也并不能比 session 更高效 |
55
jy01264313 2017-08-10 23:53:07 +08:00 1
session 不一定需要存在服务器端,cookie 里面存 session 一样可以非常简单
|
56
msg7086 2017-08-11 00:00:42 +08:00 2
Session 是一个更宽泛的概念。
JWT 原则上也是一种 Session。 Rails 里用 Cookie based session 已经很久了,也是把 Session data 序列化加密以后存储 Cookie。 主要缺点还是 Session data 比 Session ID 更耗费流量,每次请求(甚至当前域的静态文件也是)都要带上完整的 Session,非常耗费流量。另外 Cookie 本身还有长度限制问题。 |
57
cnnblike 2017-08-11 02:38:23 +08:00 2
我感觉 jwt 有一个不好实现,就是怎么保证服务器可以把用户踢下去呢?
如果要能实现踢下线这个操作的化,你得在服务器端保存一个"latest effective timestamp"之类的,这又和一般的 session 又有什么区别呢? |
58
rason 2017-08-11 07:51:52 +08:00 via iPhone 1
感觉有人说的 session 非楼主所指的 session,具体与含义。
|
59
rason 2017-08-11 08:01:05 +08:00 via iPhone 1
使用 jwt 就不需要用集中式 session 管理来解决分布式的问题,我只能说,jwt 是一种比 session 更优的会话方案。
|
60
simaguo 2017-08-11 08:57:59 +08:00 1
最近用 jwt 正开发一个项目,体验中
|
61
Clarencep 2017-08-11 09:14:31 +08:00 1
个人感觉是 JWT 太长了
|
62
mywaiting 2017-08-11 09:29:21 +08:00 3
楼主目测只是看看文档,没有实际经手一个完整的项目
session 只是一个概念,一个记录 client 状态的实现,这个角度来说,JWT 本身也是一种 session。而 HTTP 都是使用 cookie 来实现了,这点谁都一个卵样(极少数使用 URL 的 id 化来实现,然后无法避免一旦有人无意分享了这个 URL,顺便也把自己的登陆状态分享出去了,比如以前新浪微博的手机版,靠 URL 里面的 gsid 参数来识别登陆的状态)。 JWT 只是签名过的 cookie,一个有实现规范的协议而已,事实上就是一个加密的 cookie,保存信息容量有限,无法解决服务端过期的实现(可以服务端记录 JWT id 和 timestamp 做到,不过这样不是又回到服务器 session 的实现了么?)还有就是楼上的持久化劫持的问题,在需要大量保存用户数据(超过 JWT cookie 容量的时候),一样需要服务器侧的支持,此时又退化为服务器侧的 session 了。而 JWT 所说的只保存用户 id,根本就是伪命题,数据回到服务器,只有 id 你一样要根据 id 去数据库或者缓存查一次用户 user 自己的其他信息如 name,mail,这时候又退化为服务器侧的 session 了,完全失去其分布式的初衷 服务器的 session 就是一个随机字符串 id 的 cookie 放客户端,服务器来保存该 id 对应的数据,的确是用分布式 session id 同步的问题。然而,多数时候,session id 的保存都在单独的 redis 服务器上了,不是淘宝那样的存在,几台 redis 足够你刷到数千万用户了,根本没有什么好担心的 说到底,还是 HTTP 这个协议已经决定了你的实现的方法,session 能折腾的方向实在不多。而大多数网站的实现都是服务器端的 session,此时,你就应该好好想一下,JWT 是不是有天生的缺陷。 再者退一万步来说,身份识别和保持这事情,不使用中心化的识别和认证是及其困难的事情,无论现在的各种签名、各种算法,其背后还是有着中心化的担保和识别的。 道理都是简单如此 以上,希望有用 |
63
littleshy 2017-08-11 10:04:03 +08:00 1
jwt 适合分布式,但我真正需要分布式的网站也就那几家大厂。
还不如用 session。 |
64
baiyi OP |
65
kiddult 2017-08-11 11:00:50 +08:00 1
@baiyi JWT 存的用普通的也能搞定,不过感觉你说的是不是 J2EE 里面的 session ?实际用的时候,除非个人小站,不然不会把 session 放本地内存
|
67
baiyi OP |
68
superboss01 2017-08-11 11:59:57 +08:00 2
问这种问题就没搞清本质了(什么叫 SESSION,请参考该文字本身的意思)
COOKIE 和 JWT 从本质上看都一样的,可进行用户的身份识别和认证,实现 SESSION 会话,不过侧重点不一样 COOKIE 是传统的久产物,只有一个身份字符串 JWT 虽然也是一个字符串,不过自身包含了身份字符串 TOKEN,签名以及签名方式和一些额外的信息 你可以自己实现一套自己的 JWT,比如 base64(jsonencode([{name:'enc',type:'md5'},{token:'xxx'},{sign:''}])),当然了 JWT 有自己的一套标准 共同点: COOKIE 是浏览器自身进行了存储,在通信时候浏览器将 COOKIE 信息从存储地方取值后附加到了 HTTP 的 HEADER 头部进行了请求(也可以放入查询字符串) JWT 也是将信息放入 HTTP HEADER 头部(你放入查询字符串也可以) COOKIE JWT 都有过期时间,都有身份表示字符串 微小不同点: COOKIE 依赖了浏览器和 COOKIE 自身的存储方式(比如域名相关) 而 JWT 则脱离了这样约束,特别是当下浏览器和 APP 以及分布式的环境下则体现出了优势了 |
69
ieiayaobb 2017-08-11 12:01:01 +08:00 1
其实服务端注销这个需求是 JWT 的痛点,当然你可以把 JWT 当做一个 id_token 存在服务端,但这样做就舍弃了 token 的无状态的优势了
|
70
superboss01 2017-08-11 12:07:42 +08:00 1
@ieiayaobb 前 2 天都帮人做过 JWT 的实现 业务 JWT 是不需要存储在服务器端的
问题就是过期问题 如果用户在登录获取到 JWT 这个字符串后 我没有采用 JWT 自身的过期,因为需要给用户再从新发送新的有效期 JWT 很明显有些麻烦了 而是采用了 REDIS 进行下 JWT 缓存 用户在进行下 API 请求的时候,我就将该 JWT 在 REDIS 里面进行时间的延长 |
71
sampeng 2017-08-11 12:09:01 +08:00 1
每次有人要用 jwt。我就想怼回去。。。
个人感觉 jwt 更多的是在移动应用里面使用。为啥要这么用? 因为我见过的移动端开发都说不能支持 cookie。也就不能支持 session。既然要 url 传 sessionid。那就干脆 jwt 了。。 这个逻辑我也表示很无语。。。 |
72
baiyi OP |
73
baiyi OP |
74
orFish 2017-08-11 12:48:43 +08:00 1
jwt 本质也是 token,只是可以解析后获得部分用户信息等。
jwt 经常也都是要存 redis 等缓存的 |
75
jarlyyn 2017-08-11 12:51:23 +08:00 1
楼主的问题无非是吧 session 数据放在服务器端还是客户端而已。
本质上还是一个东西。 |
76
baiyi OP |
78
newkedison 2017-08-11 14:40:42 +08:00 1
|
79
baiyi OP |
80
newkedison 2017-08-11 15:06:51 +08:00 1
|
81
baiyi OP |
82
orFish 2017-08-11 15:14:45 +08:00 1
@baiyi 是不需要,但是,如果有 jwt token revoke 的需求,还是要存 cache 啊,而且 jwt 用的话,key 一旦泄露就 GG
我们之前项目中用 jwt,但是还是需要去 redis 做校验。 |
83
baiyi OP @orFish #82
jwt 需要注销, 我的设想是: 服务器端既然不能控制会话状态, 那么, 可以控制用户资源状态, 给其添加一个注销时间, 时常 = jwt 的最大有效期, 每次 jwt 校验过后, 还要校验是否有符合注销时间 至于 key 被偷不再考虑的范围内 |
87
orFish 2017-08-12 22:05:49 +08:00
@baiyi 显然你还是没理解我意思。。。假如,你现在给用户 A 发放了个 token TokenA, jwt 可以从此 token 得到过期时间是 2017-09.01 ,但是用户在 2017-08-20 修改了密码,需要把 TokenA revoke 掉使其失效,你不存 cache 你能实现么。(不考虑 token 黑名单)
|
88
baiyi OP @orFish #87 你知道你的 jwt 发布的过期时间是多少, 比如说 7 天, 那么过期时间 -7 天, 得出生成的时间戳, 或者 jwt 里也有存储发布时间的。 注销时间是 7 天内的, 那么很容易得出这个 jwt 过期了
|
90
baiyi OP @orFish #89
恩, 我是这么想的, 过期时间是 2017-09-01, 那么已知你的过期时间和总有效期, 因为毕竟是你签发的吗,你一定知道总有效期的。 假设总有效期是 7 天 , 那么签发日期就是 2017-08-24,8 月份有 31 号, 我没算错吧。 用户在 2017-08-27 提出注销请求, 服务器记录 2017-08-27 的注销时间, 有效期为 jwt 的总有效期。 这时 2017-08-24 签发的请求过来后, 就能判断出他的请求失败了 |
92
lml12377 2017-08-31 10:31:26 +08:00
@Mutoo 多负载机的会话解决方案,即使牵扯到 REST,不也应该是集中存储 session 吗(比如 redis 集群,或者存到库中)?
|
93
lml12377 2017-08-31 10:43:11 +08:00
@Mutoo 我可能理解错了~正常是不是客户端使用账号密码请求 api,校验成功生成 token,不管是哪一台负载机 token 统一存到一处比如 redis,比如网页端则可以将 token 关联到 cookie 来维持 web 端的登陆?刷新页面,网页后端从 session 中拿到 token 请求 api ?
|
94
gmywq0392 2017-09-01 09:51:50 +08:00
hack news 上有很多讨论,看上去主要是对一个既有的 token 没有一个理想的失效机制,但在 token 里面放个 expire 的方式感觉就能解决了哇。v2er 有兴趣可以看下他们的讨论,看看我们还有什么未论及的弊端。
1. https://news.ycombinator.com/item?id=13865459 2. https://news.ycombinator.com/item?id=11895440 3. https://news.ycombinator.com/item?id=14290114 还有一个问题就是 jwt 头的算法标识,如果 token 里的加密算法是由客户端决定的,那么服务器的每次校验签名,都是根据那个算法来的,这个会让服务器显得很肉鸡。这个个人觉得相当尴尬,不是我们开发人员能允许的存在。 另外啊,使用上来讲,jwt 和传统的 session cookie 就像传值和传引用一样,如果想够纯粹那就不能每次都 hit db or redis etc,这时 token 里的内容就会敏感起来,会担心它的泄密与可靠,在这个点上,假设 token 是不对外暴露的( https ),难以模仿的或者说模仿成本过高的(哈哈一个可行性猜测),那么适用性就广泛些。做不到以上的话,还是建议只用作微服务间内部的通信凭证,与 C 端的通信,由服务网关那维护 session 的机制。哈哈这里又 stateful 了。 |
95
gmywq0392 2017-09-01 09:57:08 +08:00
@gmywq0392 干,应该是 hacker news。第二段有个错误,“如果 token 里的加密算法是由客户端决定的” 应该为 “如果 token 里的加密算法是可以由客户端决定的”
|
96
baiyi OP @gmywq0392 #94 jwt 的算法不是客户端决定的, 是另外一台服务器决定的, 因为 JWT 并不是客户端生成的, 他方便的是多台服务器间的沟通.
token 主要的失效问题是只能被动失效, 就是过期时间, JWT 中有这个规范. 现在想要的效果是主动失效, 按照我上面回答中的处理方法, 服务器还是要存储 context. 虽然比存储 session 要少得多, 但还是有些不太好. |
98
Zzdex 2018-06-08 10:16:12 +08:00 via iPhone
项目没用 JWT 原因之一就是无法服务端注销 只能前端假注销
JWT 想实现 那就必须在服务端留 key 那不就和 session 一样了吗 |
99
JasonLaw 2021-03-07 15:36:11 +08:00 via iPhone
|