cookie,session,token 的理解
最开始的服务器基本上就是支持文档的浏览, 只支持浏览功能,使用场景简单,不需要记录用户在某一段时间内的浏览记录,每次请求都是独立的 http 请求。
随着交互式应用的兴起,如线上购物,都需要验证用户后再进行操作,这样,就会有一个问题,如何管理交互的会话,从而知道那哪些操作是哪些用户发起的(用户添加购物车、结账等操作),因为 http 请求本身是无状态的;这个时候就需要会话标识(session ID),服务器为每个验证通过的用户生成一个唯一的会话标识(生成规则各异),用户每次向服务器发起 http 请求时,会把会话标识一并发送过来,这样服务器就可以区分用户了。
上述的解决方案虽然很好的,解决了区分用户的问题;但是,服务器为了区别所有产生会话的用户,需要保存所有用户的会话标识(session ID),如果同一时间段内,访问服务器的用户多了, 就需要维护大量的会话标识,以淘宝为例的话,这个数字将是恐怖的。这些会话标识对服务器说来说,是一个巨大的开销 , 同时,也严重的限制了服务器扩展能力。假如,有一个由两个服务器组成的集群, 用户通过 服务器 1 登录, 此时会话标识会保存在 服务器 1上, 假如该用户的下一次 http 请求是 服务器 2 处理,因为该用户没有在 服务器 2 上进行验证操作,服务器 2 无法继续处理该请求。其实,也是可以规避上述的问题,就是同步两个服务器的会话标识,但是这回有另外的开销,同时也相对低效。也可以使用和 Redis 一样的思想,将会话标识(session ID)使用专门的服务器保存,为了使保存会话标识的服务器可以稳定的提供服务,就需要使用一定的手段,例如集群的方式。
为了简化会话的管理,后来就出现了 token,token 是怎样工作的呢。就是,当用户登录系统,服务器验证通过了该用户, 服务器会生成一个令牌(token)返回给该用户,但是服务器并不保存,下一次用户再次发起 http 请求时, 会将这个 token 通过 http header 发送至服务器。
既然服务器没有保存这个令牌又怎么确定这个用户是已经登录过的用户呢?秘密就在这个 token 上,需要使用一个只有服务器知道的**,对一段数据使用生成算法(例如 HMAC-SHA256),从而生成 token,由于**只有服务器才知道,也就无法伪造 token。
用户再次请求时,会将 token 一并发送至服务器,服务器再对数据使用生成算法算法和同样的**,生成 token,然后,把这个新生成的 token 和 http 请求中的 token 做比较, 如果相同, 就可以确定这个用户已经登录过。
使用 token 对用户验证的过程如下图
有了 token 服务器不用再保存 session ID 了, 只需要生成 token , 然后验证即可。实际的意义就是使用 CPU 的计算时间换取 session ID 存储的空间;同时,服务器集群也可以轻松地做水平扩展,当用户访问量增大时,直接加机器即可,无需关注 session ID。
Cookie
cookie 就是浏览器里,能长久保存的一种数据,就是浏览器实现的一种数据存储。
cookie 的内容由服务器生成,浏览器把 cookie 的实际内容以 键值对 的形式保存到固定目录下的文本文件中,下一次请求同一网站时会把该 值 发送给服务器。cookie 不会占据太多磁盘空间,且每个域的 cookie 数量是有限的。
Session
session 在前面已经讲的很清楚了,就是服务器为了区分用户,为每个用户分配的不同的会话标识(session ID),然后,用户每次向服务器发起 http 请求时,都带上这个会话标识,服务器通过比对已经保存的 session ID 从而确认用户身份。服务器使用 session ID 把用户的信息临时保存在服务器上,用户离开系统后 session ID 会被销毁。
弊端
1、每次用户登陆系统,用户验证通过后,服务器都需要去创建会话标识并且保存起来。当大量用户发请求时,内存开销会很大。
2、使用 session ID 也会伴随着可扩展性问题。
3、存在 CSRF(跨站请求伪造)的风险,用户在访问某些网站以后,没有及时退出,就容易受到跨站请求伪造的攻击。
Token
当前在大多数系统都是使用 token 进行用户认证。token 无状态、易扩展,同时,支持移动设备、跨程序调用,且相对来说更安全。