关于ZAKER 融媒体解决方案 合作 加入

由 Session 到 Token 的身份验证演变过程理解 Session、Cookie、Token

51CTO 01-19

本文将从 Web 应用 由传统身份验证到基于 Token 的身份验证的演变过程的角度,介绍 Session、Cookie、Token。

很久以前,Web 应用基本用作文档的浏览,如网络黄页。既然仅仅是浏览,因此服务器不需要记录具体用户在某一段时间里都浏览了哪些文档,每次请求都是一个新的 HTTP 协议,对服务器来说都是全新的。

基于 Session 的身份验证

随着交互式 Web 应用的兴起,比如,购物等需要登录的网站。引出了一个新的问题,那就是要记录哪些用户登录了系统进行了哪些操作,即要管理会话 ( 什么是会话 ? 简单的讲如果用户需要登录,那么就可以简单的理解为会话,如果不需要登录,那么就是简单的连接。 ) ,比如,不同用户将不同商品加入到购物车中, 也就是说必须把每个用户区分开。因为 HTTP 请求是无状态的,所以想出了一个办法,那就是给每个用户配发一个会话标识 ( Session id ) ,简单的讲就是一个既不会重复,又不容易被找到规律以仿造的随机字符串,使得每个用户的收到的会话标识都不一样, 每次用户从客户端向服务端发起 HTTP 请求的时候,把这个字符串给一并发送过来, 这样服务端就能区分开谁是谁了,至于客户端 ( 浏览器 ) 如何保存这个 " 身份标识 ",一般默认采用 Cookie 的方式,这个会话标识 ( Session id ) 会存在客户端的 Cookie 中。

虽然这样解决了区分用户的问题,但又引发了一个新的问题,那就是每个用户 ( 客户端 ) 只需要保存自己的会话标识 ( Session id ) ,而服务端则要保存所有用户的会话标识 ( Session id ) 。 如果访问服务端的用户逐渐变多, 就需要保存成千上万,甚至几千万个,这对服务器说是一个难以接受的开销 。 再比如,服务端是由 2 台服务器组成的一个集群, 小明通过服务器 A 登录了系统, 那 session id 会保存在服务器 A 上, 假设小明的下一次请求被转发到服务器 B 怎么办 ? 服务器 B 可没有小明 的 session id。

可能会有人讲,如果使小明登录时,始终在服务器 A 上进行登录 ( sticky session ) ,岂不解决了这个问题 ? 那如果服务器 A 挂掉怎么办呢 ? 还是会将小明的请求转发到服务器 B 上。

如此一来,那只能做集群间的 session 复制共享了, 就是把 session id 在两个机器之间进行复制,如下图,但这对服务器的性能和内存提出了巨大的挑战。

因此,又想到如果将所有用户的 Session 集中存储呢,也就想到了缓存服务 Memcached ——由于 Memcached 是分布式的内存对象缓存系统,因此可以用来实现 Session 同步。把 session id 集中存储到一台服务器上, 所有的服务器都来访问这个地方的数据, 如此就避免了复制的方式, 但是这种 " 集万千宠爱于一身 " 使得又出现了单点故障的可能, 就是说这个负责存储 session 的服务器挂了, 所有用户都得重新登录一遍, 这是用户难以接受的。

那么索性存储 Session 的服务器也搞成集群,增加其可靠性,避免单点故障,但不管如何,Session 引发出来的问题层出不穷。

于是有人就在思考, 为什么服务端必须要保存这 session 呢, 只让每个客户端去保存不行吗 ? 可是服务端如果不保存这些 session id ,又将如何验证客户端发送的 session id 的确是服务端生成的呢 ? 如果不验证,服务端无法判断是否是合法登录的用户,对,这里的问题是验证, session 只是解决这个验证问题的而产生的一个解决方案,是否还有其它方案呢 ?

基于 Token 的身份验证

例如, 小明已经登录了系统,服务端给他发一个令牌 ( Token ) , 里边包含了小明的 user id, 后续小明再次通过 Http 请求访问服务器的时候, 把这个 Token 通过 Http header 带过来不就可以了。

服务端需要验证 Token 是自己生成的,而非伪造的。假如不验证任何人都可以伪造,那么这个令牌 ( token ) 和 session id 没有本质区别,如何让别人伪造不了 ? 那就对数据做一个签名 ( Sign ) 吧, 比如说服务端用 HMAC-SHA256 加密算法,再加上一个只有服务端才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为 Token 发给客户端, 客户端收到 Token 以后可以把它存储起来,比如存储在 Cookie 里或者 Local Storage 中,由于密钥除了服务端任何其他用户都不知道, 就无法伪造令牌 ( Token ) 。

如此一来,服务端就不需要保存 Token 了, 当小明把这个 Token 发给服务端时,服务端使用相同的 HMAC-SHA256 算法和相同的密钥,对数据再计算一次签名, 和 Token 中的签名做个对比, 如果相同,说明小明已经登录过了, 即验证成功。若不相同, 那么说明这个请求是伪造的。

这样一来, 服务端只需要生成 Token,而不需要保存 Token, 只是验证 Token 就好了 ,也就实现了时间换取空间 ( CPU 计算时间换取 session 存储空间 ) 。没了 session id 的限制, 当用户访问量增大, 直接加机器就可以轻松地做水平扩展,也极大的提高了可扩展性。

【编辑推荐】

不了解 Cookie、Session、Token?一文给你整明白

【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0

以上内容由"51CTO"上传发布 查看原文
相关标签 storage过程

觉得文章不错,微信扫描分享好友

扫码分享