一、前言
这篇博客来谈一谈Web
应用中广泛使用的Cookie
、Session
以及Token
机制,它们在Web
应用中起着至关重要的作用,同时也是面试中的高频考点。这篇博客我主要来介绍一下这三种东西的相关概念和它们实现的原理,以及它们之间的区别。
二、正文
2.1 为什么需要它们
首先来说第一个问题,我们为什么需要这三样东西?稍微了解过HTTP
的应该知道,HTTP
协议是一个无状态的协议。什么是无状态?就是说,HTTP
服务器对每一条请求一视同仁,不会记录每一条请求的状态,比如是由谁发出的,所有的请求对它来说都是陌生的。就算你连续向同一个服务器发送两条请求,对它来说,这也是两条完全不相关的请求。但是,我们会发现这样一个现象,当我们在一个网站登录后,服务器就好像认识了我们,我们发送出去的请求,都能得到与我们自身相关的响应。比如说我们在淘宝登录后,点击购物车,就能够看见我们自己加入的商品;而如果我们没有登录,就会被拦截下来,跳转到登录页面。这是为什么呢?不是说HTTP
是无状态的吗。其实,这就是依赖于上面的三种机制。
2.2 Cookie
Cookie
其实就是浏览器保存在电脑中的一些文本数据,它们都是key-value
形式的,其中包含了我们自己以及服务器的一些信息。当我们向一个服务器发送请求时,服务器可能希望我们在本地保存一些数据,这时候就会在响应报文的首部中加上一个名字叫做Set-Cookie
(或Set-Cookie2
,取决于版本)的首部行,后面跟着希望浏览器保存在本地的数据。浏览器接收到响应报文,发现了其中的set-Cookie
字段,就会将其中包含的数据保存在电脑中,同时也记录下服务器的地址。那这些数据有什么用呢?当我们下一次向这个服务器发送请求时,这些Cookie
数据就会随着请求报文一起被发往服务器,服务器接收到Cookie
数据,就能以此识别当前发送请求的是哪一个客户端,或者说能够识别这个客户端,从而做出对应的响应操作。这个过程如下图所示:
由于Cookie
是保存在本地文件中,所以它能够被长期保存,只需要将过期时间设置的长一些。这里还需要说明的是,由于Cookie
将数据存储在本地,所以它其实是不安全的,因此浏览器允许客户端禁用Cookie
。除此之外,Cookie
能够保存的数据大小也有限制,单个Cookie保存的数据不能超过4K
。
2.3 Session
Session
的中文翻译叫做:会话,表明它就是客户端与服务器的一次会话。与Cookie
不一样,Session
是由服务器进行维护的。当客户端向服务器发送一个请求时,服务器会为发起这个请求的客户端创建一个对象,并存储在服务器的一个集合中,同时生成一个唯一的SessionId
来标识这个对象,而有关当前用户的信息可以存储在这个对象中。当服务器给用户发送响应报文时,也会将SessionId
放入响应报文的Set-Cookie
首部后,用户接收到响应报文后,检测当Set-Cookie
首部行,将其中包含的SessionId
存储在本地。在下一次客户端向服务器发出请求时,将SessionId
从Cookie
中读出,并发往服务器。服务器检测到SessionId
后,在存储Session
对象的集合中查找此SessionId
对应的对象,即可获得用户的相关信息。最常见的一种用法就是用户登录:当用户登录后,服务器在Session
中存储用户的身份信息,如userId
。当接收到一个用户的请求后,查询Session
对象,若其中包含userId
,表示这个用户已经登录,同时可以通过获取到的userId
查询用户私人的数据。而服务器并不会一直维护Session
,它会在用户退出浏览器、或者在一段时间没有接收到这个用户的请求后,将Session
清除。
但是,Session
也存在一些问题,比如对于每一个用户,服务器都需要维护一个或多个Session
,若一段时间内访问服务器的用户数量庞大,将导致服务器需要维护大量的Session
对象,严重占用资源。除此之外,当今的Web
服务器,都采用了集群的技术,集群中的每一台服务器的Session
都是独立的,要实现Session
共享也是一个比较麻烦的事情。最后再提一点,浏览器可以禁用Cookie
,此时SessionId
将无法存储在Cookie
中,这个时候浏览器的一般做法是在URL
中放入SessionId
,这样在用户没有关闭网页之前,这个SessionId
就不会丢失。
2.4 Token
Token
的主要作用是对用户做身份验证,我们一般称它为:令牌。当我们要登录一个网站时,输入账号密码发送到服务器端。此时服务器查询数据库,验证账号密码,若验证成功,则服务器根据一些特殊的加密算法,计算出一个Token
(一串字符),将其发送给客户端,同时将用户的身份信息也发送过去,比如userId
。客户端接收到响应后,将Token
存储在Cookie
或者本地内存中,再次请求时将Token
以及userId
发送到服务器。服务器接收到一个请求后,根据客户端的相关信息,重新计算Token
,若这个新的Token
值与客户端发来的Token
一致,表示用户之前已经经过验证,可以直接获取服务器数据。
是不是感觉和Session
有些类似,但是实际上两者差别还是比较大的。服务器计算Token
值需要用到用户的个人信息(比如说客户端的mac地址
),以及只有服务器自己知晓的密匙,这也就保证了Token
对于每一个客户端来说都是唯一的,而且由于密匙只有服务器自己知道,所以黑客无法模拟服务器计算Token
值,然后发送虚假请求。服务器只要检测到错误的Token
,就不会允许客户端的请求,而是要求客户端先进行验证。而且,对于每一个请求,服务器不需要像Session
一样,保存客户端的身份信息,它每次只需要计算Token
进行比较即可,也就是它不会破坏HTTP
的无状态性。
但是,这也意味着Token
一旦被他人截获,对方就可以使用你的身份,对服务器发出请求。所以,Token
一般都是基于HTTPS
使用,而不是基于不安全的HTTP
使用。而且存储在本地时,也会进行相应的加密处理。
2.5 三者之间的区别
(1)Session与Cookie的区别
- 安全性:
Session
比Cookie
安全,Session
是存储在服务器端的,只有服务器自己可以查看Session
存储的数据,但是Cookie
是存储在客户端的,容易被非法读取。 - 存取值的类型不同:
Cookie
数据保存在文本文件中,所以只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session
可以存任意数据类型,因为它存储在服务器的内存中,本质上是一个对象。 - 有效期不同:
Cookie
可设置为长时间保持,比如我们经常使用的默认登录功能,Session
一般失效时间较短,客户端关闭(默认情况下)或者Session
超时都会失效。 - 存储大小不同: 单个
Cookie
保存的数据不能超过4K
,Session
可存储的数据远高于Cookie
,但是当服务器Session
过多时,会占用过多的服务器资源,造成服务器运行缓慢。
(1)Session与Token的区别
Session
和Token
其实是有本质区别的,它们并不是用在同一件事情上。Session
的主要作用是,存储客户端与服务器的会话信息,也就是服务器需要知道当前发出请求的客户端的相关信息,所以它维护一个集合,存储Session
对象,其中包含该客户的信息。只是,Session
的这种机制也可以用来做验证,只要服务器有当前客户的Session
,且其中包含了相关信息,服务器就认为当前客户已经验证过了。
但是Token
不同,它不要求服务器维持客户端的状态,它的作用仅仅就是对发送请求的客户端做验证,防止一些网络攻击。只有通过验证的客户请求,服务器才会给予响应,否则会要求其先进行验证。而且,Token
的验证方式在安全性上要高于Session
。这两者并不冲突,我们完全可以在服务器使用Token
对客户端进行校验,然后使用Session
保存会话信息。
三、总结
上面对Cookie
、Session
以及Token
做了一个大致的介绍,相信看完之后,能够让人对这三者有一个大致的了解,但是想要真正深入地学习它们的原理及实现机制,仅仅上面这些内容是完全不够的,还需要更加具体的资料进行学习。