1、在很久以前,Web的工作只是文档浏览的一种方式,无论谁发请求给服务器,它都返回一样的文档,每一个请求对服务器而言都是全新的,是无状态的,不会记住刚刚是谁发的http请求。
2、但是随着Web应用的兴起,出现了像购物网站,需要登录的网站,就会面临一个问题,那就是要管理会话,必须知道是哪些人登录系统,哪个用户发来的请求。也就是说要区分不同的用户。但http是无状态请求的
什么是无状态呢
就是一旦客户端和服务器的数据交换完毕,就会断开连接,再次请求时才会重新连接,此时服务器无法判断用户身份,此时cookie和session就出现了。就是为了解决http无状态请求这个问题的
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用Response Header
的Set-Cookie
向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来(自动保存起来了,不用手动保存)。当浏览器再请求该网站时,浏览器通过Request Header
的Cookie
把请求的网址连同该Cookie一同提交给服务器(也是自动带上的cookie的)。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
存储位置(客户端):
硬盘
里面)内存
里面缺点:
当 Cookie 带 httpOnly
选项时,客户端则无法通过 js 代码去访问(包括读取、修改、删除等)这个 Cookie。
除了使用Cookie一种方法,Web应用程序中还经常使用第二种方法Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。
1、用户向服务器发送用户名和密码
2、服务器通过验证后,会在当前会话(session)里面保存相关数据,比如用户角色,登陆时间等;
3、服务器会通过Response Header的Set-Cookie向用户返回一个sessionId,客户端存入Cookie中
4、用户随后的每一次请求,都会通过Request Header的Cookie,将sessionId发送给服务器
5、服务器收到 sessionId 后,找到之前保存下来的数据,由此得知用户身份
注意点:
Cookie和Session的区别
引入背景(session不足):
1、服务器压力增大:
session是保存在服务端的,客户端只需要保存自己的sessionId,但是服务端要保存所有用户的sessionId,如果访问服务器的人多了,可能有几十万,几百万,这对服务器来说是一个巨大的开销。
2、CSRF跨站伪造请求攻击:
session是基于cookie进行用户识别的,cookie如果被获取,用户就有可能受到CSRF的攻击
3、拓展性不强:
如果将来搭建了多个服务器,比如用多个服务器组成的一个集群,虽然每个服务器处理的业务逻辑都是一样的,但session是保存在服务器里面的,多个服务器之间是不共享的,用户第一次访问服务器A,A将该用户的session保存起来,但是当用户下一次请求的是服务器B,此时B里面就找不到该用户的信息,就判定该用户不合法。
针对session拓展性不强,人们想出了一些小伎俩:
对小小的session来说,以上的方法都不好,负担沉重
由此,token就应运而生
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
Token把状态交给用户来管理,这样的确解决了空间问题,但是如果服务器不保存这些会话标识(session要保存在服务器端),我们又改如何确定这些会话标识是不是由我生成的呢。如果无法验证他们是不是合法的,就无法保证登陆的安全性
Token解决这个问题的关键在于验证
验证的关键的生成一个签名,一般服务器运用哈希算法(比如HMAC-SHA256
),加上只有服务端才知道的密钥,对数据(比如userId
)做一个签名,把这个签名和数据一起作为token发给客户端,由于密钥别人不知道,所以不能伪造token
这个token服务端不用保存,当客户端把这个token发过来时,服务端再用同样的哈希算法对数据做一个签名,看看此时生成的签名和token带回来的签名是否一致,如果一致,我知道用户已经登录过来,并且可以直接获取到用户的id。
其验证过程如下:
Token的验证是无状态的,我们不用将用户信息保存在服务端,每一次请求都要带上token,token应该在http的头部发送从而保证了http请求无状态。这样我们就可以减轻服务端的压力,实现了用计算时间(因为进行加密解密需要消耗时间)换取空间,session是空间换时间同时也增强了可拓展性
什么是token及怎样生成token、《JSON Web Token 简介》
payload
,以及Header
信息进行Base64
加密,形成密文payload密文,header密文。xxxxx.yyyyy.zzzzz
,每一部分都是基于base64url编码的值token优势:
1、无状态、可扩展
在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成 一些拥堵。但是不要着急。使用tokens之后这些问题都迎刃而解,因为tokens自己hold住了用户的验证信息。
2、安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。
3、可扩展性
Tokens能够创建与其它程序共享权限的程序。例如,能将一个随便的社交帐号和自己的大号(Fackbook或是Twitter)联系起来。当通过服务登录Twitter(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。
4、多平台跨域
我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。Having our API just serve data, we can also make the design choice to serve assets from a CDN. This eliminates the issues that CORS brings up after we set a quick header configuration for our application.只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。Access-Control-Allow-Origin: *
Cookie实际上是一小段的文本信息。是为了解决http无状态请求的问题。客户端请求服务器,如果服务器需要记录该用户状态,就使用Response Header
的Set-Cookie
向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来(自动保存起来了,不用手动保存)。当浏览器再请求该网站时,浏览器通过Request Header
的Cookie
把请求的网址连同该请求域下(请求谁就带上谁的cookie)的Cookie一同提交给服务器(也是自动带上的cookie的)。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
cookie属性 | 作用 |
---|---|
name字段 | 一个cookie的名称 |
value | 一个cookie的值 |
domain | 可以访问此cookie的域名 |
path | 可以访问此cookie的页面路径 |
Size | cookie大小 |
httponly | 若此属性为True,客户端则无法通过 js 代码去访问(包括读取、修改、删除等)这个 Cookie。 |
secure | 设置是否只能在https 下来传递此条cookie。 |
expires/Max-Age | 设置cookie超时时间。如果设置的值为一个时间,则当到达该时间时此cookie失效。不设置的话默认是session,意思是cookie会和session一起失效,当浏览器关闭(并不是浏览器标签关闭,而是整个浏览器关闭)后,cookie失效。 |
SameSite | 不跨站发送cookie到第三方网站,减少 CSRF 的攻击;Strict (仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致);Lax (允许部分第三方请求携带 Cookie,除了get请求可以);None (无论是否跨站都会发送 Cookie);之前默认是 None 的,Chrome80 后默认是 Lax |
《预测最近面试会考 Cookie 的 SameSite 属性》、《阮一峰Cookie 的 SameSite 属性》
使用:
document.cookie='名字=值'
cookie不足:
4kb指的是:
《Cookie有数量和大小的限制》、《浏览器cookie数量和大小限制》
各浏览器的cookie每一个name=value
的大小大概在4k;所以4k并不是一个域名下所有的cookie共享的,而是一个名(name
)、值(value
)和等号(=
)的大小;而对于每个域名name
个数的限制,发现ie10大概是50个,如果超过了50个,最前面设置的就会挨删除把新的放进去.当出现这种溢出替换的过程时,就会导致当前进程的ie的这个域名无法访问,需要重启浏览器才行;
为了弥补Cookie的局限性,WebStorage就产生了。WebStorage是HTML5中新增的本地存储解决方案,包含了SessionStorage和LocalStorage两类。有了WebStorage之后,Cookie就能够安心只作为客户端与服务器交互的通道(保持客户端状态)了,不用再操心存储的事情。
WebStorage两个主要目标:
(1)提供一种在cookie之外存储会话数据的路径。
(2)提供一种存储大量可以跨会话存在的数据的机制。
将数据保存在客户端本地的硬件设备(通常指硬盘,也可以是其他硬件设备)中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用。
特点(默认也不能跨域访问):
使用:
localStorage.setItem(name, val);
localStorage.getItem(name);
使用场景:
译-在多个标签页之间共享sessionStorage
将数据保存在session对象中。所谓session,是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。session对象可以用来保存在这段时间内所要求保存的任何数据。
特点:
使用:
sessionStorage.setItem('key','value')
sessionStorage.getItem('key');
使用场景:
tip:这两者的区别在于,sessionStorage为临时保存,而localStorage为永久保存。
IndexedDB是一种低级的API,使用索引来实现对其间存储数据的高性能搜索,用于客户端需要存储大量结构化数据。他可以看作是一个运行在浏览器上的非关系型数据库。既然是数据库了,那就不是5M、10M这样小打小闹的级别了,理论上来说,IndexedDB是没有存储上限的,一般来说不会小于250M。另外,它不仅可以存储字符串,还可以存储二进制数据