趣谈HTTP会话与用户登录

408 阅读7分钟

前言

好久不见,各位小伙伴。差不多一年多没有更新,没想到收到了这么多的留言和关注,感谢大家一直以来的支持。最近我们团队的小伙伴也开发了一个小,程,序前端面试题宝典,收录了600多道前端面试题,希望能为正在面试路上的小伙伴助一臂之力。

接下来进入正题,希望你们喜欢~

一个故事让你掌握Http会话和用户登录的实现原理

刚开始接触http协议的小伙伴,一般都会听到一个词语,叫 “无状态” 。

其实在面试中经常会提到 HTTP 协议,很多同学会能回答出这2点:基于TCP、无状态。

那么,这个无状态,到底是什么意思呢,以及由此引出的其他概念,比如 session、cookie-based session、JWT又是怎么回事?

HTTP无状态

简单的理解,无状态就是没有记忆功能

如果比作一个人,那这个人就是没有记忆的,他记不住自己认识的人,做过什么事。

或者,举个电商的🌰,比如有一家电商公司叫“有啊”(知道这个同学的应该有些年龄了:) ),你在网站上,加入了10件商品到购物车,刷新页面,发现购物车空空如也(搞不好还以为自己中了那种清空购物车的神券……),连加购物车都有bug,这还怎么愉快的剁手呢?“有啊”的工程师也发现了这个问题,决心想个方式,解决http的无状态问题。

session(会话)

那怎么能记住每个用户加了哪些商品到购物车呢?工程师想,门口的度娘火锅店,每次都是老板度娘拿了本子,客人点菜的时候,她就在本子上记下不同的客人,分别点了哪些菜,电商网站是不是也可以这么搞。

于是,工程师在server(服务器)端,写了一段代码,给每位访客,都在电脑上用一个文件(session),来记录他加入的所有商品。嗯,完美,现在可以记录下每个客人的购物车内容了。

cookie-based session

工程师A写完代码,自觉完美的他,给工程师B提交了 merge request ,准备起身去泡一杯枸杞茶。还没来得及动身,工程师B遍跑了过来,说这个方案存在严重问题,虽然在服务端有session来记录用户的购物车商品,但还是没解决,用户刷新页面之后,服务端不知道刷新页面前后,是同一个人(客户端client)的问题,毕竟 Http是无状态的

A思考了一会儿,服务端不能区分刷新页面前后是同一个客户端(client)的问题,那我就加一个什么东西,在服务端session文件生成之后,把这个文件路径(session id),发回给客户端,客户端把这个路径存在浏览器本地(cookie),后续每次都把这个路径发回给我,我就能找到上次的session文件了。

cookie-based-session.png

图片来源:sherryhsu.medium.com/session-vs-…

A再次完美的解决了眼前的问题。

上线运行一段时间以后,运维C跑来找到小A说,你这个逻辑有问题,在服务器上生成了太多的文件,快把磁盘空间占满了!小A心想,这是个问题,每次都生成一个新的session文件,即使磁盘便宜,长久也hold不住啊。那干脆给这些session文件加个过期时间,到了过期时间之后,就自动(或者被动)删除,这样不就减轻了服务器空间压力了么。

运维C听完,万一哪天短时间爆发大量请求,还是可能会把服务器磁盘打满,到时候还得给小A擦屁股;除此之外,后续准备将服务端进行集群化部署,怎么在多台服务器之间共享session也是个问题。正巧最近听到个时髦的词汇叫 JWT ,不妨叫小A去瞅瞅能不能解决这个问题。

JWT(JSON Web Tokens)

小A看了几篇JWT的文章,觉得JWT 很好很强大 ,直接干掉了服务端创建的session文件,直接把session文件内容发给客户端,反正自己在里面有签名,也不怕恶意用户篡改数据,完美!说干就干,小A拉上一两个切页面的(也可能是小A自己,毕竟有全干工程师的存在),cookie都干掉,前后端使用JWT进行用户认证,前端用 localStorage 或者 sessionStorage 存在浏览器里,空间还比cookie大,简直完美,还能顺手解决那些什么 CORS 的前端安全问题,perfect!一切都很完美,直到……

  • 有一天,用户打电话给“有啊”客服,自己手机被盗,要求客服把自己之前登录的设备都退出登录态

  • 又有一天,安全组发现某个用户访问异常,需要知道某个用户在多少设备处于登录态

token-based-session.png

图片来源:sherryhsu.medium.com/session-vs-…

总结

OK,扯了这么多废话,还是简单的总结下吧

HTTP会话总结:

  • Http无状态,每个请求都是独立的,你在同一个浏览器里连续2次访问一个网站,http不知道2次访问都是同一个人(或者客户端)

  • 实际生活中,我们是需要有状态的,即使能维持一段时间也很有意义(就像阿米尔汗的电影《未知死亡》里的15秒记忆男主那样)

  • 为了达到 “有状态” ,前人发明了 session 来代表依次会话,为了在浏览器(客户端)和服务器之间保持(识别)session,发明了 cookie 。在 cookie 里保存一个 session id ,服务端根据这个 session id 就能找到对应的会话数据

  • 后来又出来一批大神,说 session 增加了服务端的复杂度,比如在后端集群之间共享 session ,分布式的 session 存储也是一大挑战 。于是,JWT 应运而生。不在服务端保存 session 数据 (个人感觉大多数场景还是不免不了) ,把会话数据都发给客户端,加上一个签名,秘钥只在服务端有,这样在保证一定安全的基础上,大大降低了服务端复杂度、减少服务端资源。当然了,正如上面提到的JWT 方案也存在一些问题……

  • 除此之外,还有各种自定义的所谓 token ,其原理基本都上面的 cookie-based session 或者 JWT 一样

用户登录总结

有点尴尬的是,本文题目里包含了 “用户登录”,好像写到这里了,才发现没有讲用户登录的内容。不过,如果你能够比较好的理解上面的内容,用户登录说来就简单了。

通常后端会提供一个登录接口,前端发送用户名、密码之类的,之后,主要的工作就是存储用户已经登录的标记,这个标记,你可以有以下方式来存储:

  • 通常不管用户是否登录,我们都会有一个 session 数据。那我们当然可以这样,在用户登录之后,直接就在 普通的session 里,加上当前登录用户的ID之类的。后续请求到达server端时,只需要检查 session 里是否有用户ID,就可以判断用户是否已登录(这种方案,通常我在做一些内部系统的时候这样实现,毕竟实现简单)

  • 有的网站,普通session 和 用户登录状态,有不同的过期时间;或者为了更高的安全性,比如涉及用户登录的 cookie ,单独设置 httpOnly secure samesite 等属性。因此,需要单独和普通的session区别开,单独设置一个登录的cookie,也是一种方式,不过实现起来,会比第一种方案复杂一点点

  • JWT ,登录之后就把用户ID放到 JWT 里,发给前端。我个人 不建议 在 JWT里包含用户的权限等信息;我认为JWT里应该 尽量少 的存储数据,毕竟这个是公开的(虽然你可以加密),而且也会增加http请求头大小。

相关资料

最后

最后也忍不住的打一波广告,也欢迎大家关注我们的另一个掘金账号前端面试题宝典,我们也会定期更新前端面试相关的试题集锦和技术文章分享。