http是一个无状态协议
什么是无状态呢?就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的。这种无状态的的好处是快速。坏处是假如我们想要把www.zhihu.com/login.html
和www.zhihu.com/index.html
关联起来,必须使用某些手段和工具。
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,
1.第一个机制就是Cookie,cookie是存在客户端上的(浏览器),不安全,数据可以被修改
cookie 指的就是浏览器里面存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。过程如下:
服务器向客户端发送 cookie。(通常使用 HTTP 协议规定的 set-cookie 头操作,规范规定 cookie 的格式为 name = value 格式,比如账号id之类的,处于安全性考虑,不能放很重要的数据)
浏览器将 cookie 保存
每次请求浏览器都会将 cookie 发向服务器(浏览器自动发送cookie),服务端验证cookie里的数据与数据库存的数据是否一致,一致的话,身份通过
(其他可选的 cookie 参数会影响将 cookie 发送给服务器端的过程,主要有以下几种:
path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
expires 和 maxAge:告诉浏览器这个 cookie 什么时候过期,expires 是 UTC 格式时间,maxAge 是 cookie 多久后过期的相对时间。当不设置这两个选项时,会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到 cookie。)
举例:
如果用户是在自己家的电脑上上网,登录时就可以记住他的登录信息,下次访问时不需要再次登录,直接访问即可。实现方法是把登录信息如账号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登录信息即可。
保存登录信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。
还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。
这几种方案验证账号时都要查询数据库。
cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的。
Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户(自动填写地址,卡号等)。这也是Cookie名称的由来,给用户的一点甜头。
2.第二个机制就是seesion,seesion是存在服务端上的,耗服务端的内存, 并且容易发给不同的服务器(sessionid在客户端的cookie里)
session 的运作通过一个session_id来进行。session_id通常是存放在客户端的 cookie 中,比如在 express 中,默认是connect.sid这个字段,当请求到来时,服务端检查 cookie 中保存的 session_id 并通过这个 session_id 与服务器端的 session data 关联起来,进行数据的保存和修改。
这意思就是说,当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 cookie 中的connect.sid字段中。当你下次访问时,cookie 会带有这个字符串,然后浏览器就知道你是上次访问过的某某某,然后从服务器的存储中取出上次记录在你身上的数据。由于字符串是随机产生的,而且位数足够多,所以也不担心有人能够伪造。伪造成功的概率比坐在家里编程时被邻居家的狗突然闯入并咬死的几率还低。
session 可以存放在 1)内存、2)cookie本身、3)redis 或 memcached 等缓存中,或者4)数据库中
每个人只需要保存自己的session id,而服务器要保存所有人的session id ! 如果访问服务器多了, 就得由成千上万,甚至几十万个。这对服务器说是一个巨大的开销 , 严重的限制了服务器扩展能力, 如果说我用两个机器组成了一个集群, 小F通过机器A登录了系统, 那session id会保存在机器A上, 假设小F的下一次请求被转发到机器B怎么办? 机器B可没有小F的 session id啊。
3.第三个机制就是token,token保存在客户端,服务端不保存,只是验证,用CPU计算时间获取session存储空间
客户端使用用户名跟密码请求登录;服务端收到请求,去验证用户名与密码(数据库验证);验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端;
客户端收到 Token 以后把它存储起来,比如放在 Cookie 里或者 Local Storage 里;
cookie 验证主要是指 session ID 存储到 cookie 中进行的验证。token 验证主要是指 token 存储在 Authorization Header 中进行的验证。