1、HTTP是无状态协议
HTTP无状态协议是指该协议对事件的处理过程没有记忆能力,当后续的步骤需要上一步的信息时,则需要重传,即需要携带上一次的信息。如此,携带信息会越来越大,服务器响应会越来越慢。
2、Cookie
2.1、Cookie的原理及工作机制
Cookie是以键值对的形式存在的,与URL绑定关联,保存在客户端的文件里。
- 当用户访问服务器时,服务器可以通过设置
Set-Cookie这个响应头,将信息返回给客户端。 - 客户端浏览器会自动读取这些Cookie信息,并保存在当前域名下的Cookie本地文件当中。
- 当用户再次访问该服务器时,浏览器也会帮用户在本地查找与访问网站页面相关的Cookie信息。如果Cookie存在且没有过期的话,浏览器会自动将它添加到
request header的Cookie字段中,然后一起发送给服务器。 - 这样服务器就可以在每次请求的请求头当中拿到Cookie信息, 然后去做一些逻辑判断等操作。
每个Set-Cookie 表示一个 Cookie(如果有多个Cookie,需写多个Set-Cookie),每个属性都是键值对的形式(除了secure),属性间以分号加空格隔开。格式如下:
Set-Cookie: name1=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
Set-Cookie: name2=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
Set-Cookie: name3=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
除了在服务器端设置,还可以在客户端设置Cookie
document.cookie = "test3=myCookie3; domain=.google.com.hk; expires=Sat, 08 AUG 2021 16:00:00 GMT; secure"
document.cookie = "test4=myCookie4; domain=.google.com.hk; max-age=10800;"
只有name/value可以被发送至服务端,其余的参数仅仅是服务端给客户端的指示或者客户端自身的约束。
Cookie的缺陷:
- 每个域的Cookie总数是有限的,不同浏览器之间各有不同
- 大多数浏览器限制Cookie的大小为4KB
- Cookie文件中可能含有涉密信息,可能会导致信息泄露。
2.2、Cookie组成
Name/Value:
该属性是设置Cookie的名称及相对应的值,该值通常是保留Cookie中的用户信息。而认证Cookie,Value值包括Web服务器所提供的访问令牌。
Expires属性:
该属性是设置Cookie的生存周期。
- 默认情况下,Cookie是临时的,关闭浏览器,Cookie也会消失。
- 通过设置过期时间Expires属性,可以有效控制Cookie存活时间,有效期内浏览器都可以读取该Cookie信息,Cookie到期后会被从Cookie文件中删除
Path属性:
定义了Web站点上可以访问该Cookie的目录。比如,设置为"/"表示允许当前域名下的所有路径都可以使用该Cookie。
Domain属性:
指定了可以访问该 Cookie 的 Web 站点或域,默认为当前域。
Secure属性:
secure是 cookie 的安全标志,指定是否使用HTTPS安全协议发送Cookie。
HTTPOnly 属性 :
用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改。
3、Session
3.1、Session的原理及工作机制
Cookie是存储在客户端浏览器中的,Session是存在服务端服务器中的。
Session对象可以存储特定用户会话所需的所有属性、配置和信息。
- Session其实也是通过Cookie实现的。用户登录后,服务器将登录信息存储在服务端的Session中,并生成一个唯一的session_id,通过Cookie的形式发送给客户端。
- 客户端通过Cookie的机制,每次在访问服务器的时候,都会带上
session_id。 - 服务端通过Cookie拿到
session_id后,去Session中找到对应的Session信息,从而做一些逻辑处理。
3.2、Session缺点
随着访问服务器的用户数量的增多,服务器上保存的Session也日益增多,这对服务器来说是个巨大的开销,对于单个服务器的Web应用汇总,大量的Session会占用比较多的内存。
不仅如此,在分布式系统中,由于负载均衡对请求转发,这样就有可能导致同一个用户的请求分发到不同的服务器上,会出现获取不到Session的情况。
以下有三种解决方案:
- 通过
hash_ip算法将用户IP与固定服务器绑定,该服务器挂了,请求还是会分发到其他服务器,依旧获取不到Session信息 - 复制Session到所有服务器,该方法太占内存与带宽,浪费空间且无法水平扩展
- 添加一台Session服务器,所有请求先经过该服务器,如果Session服务器挂了,那么所有用户Session信息都会丢失
4、Token令牌
4.1、Token的原理和工作机制
通常意义上的token是把session中的内容都放到token中,可以明文形式或者用对称加密算法加密(加密密钥放在服务器端), 然后再把这些内容做hash签名(密钥在服务器),把内容和其签名拼接成一个字符串(这个就是token) 发送给客户端。
客户端后续请求都带上这个token,服务器首先校验token是否被篡改(根据hash签名校验),如果没被篡改而且token 也没过期,就把token中的用户信息(可能还有权限信息等等)拿出来,直接使用,不需要像session一样去查询具体用户信息。
4.2、Token的优势
- 无状态、可扩展
在客户端存储的token是无状态的,并且能够被扩展。基于此,负载均衡器将用户请求发送到任何一台服务器都可以获取到用户信息,而服务器只需要存储解析token的秘钥。 - 安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。
token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。 - 可扩展性
使用token时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的token。如使用微信登录微博。 - 多平台跨域
只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。
总结
HTTP请求是无状态的,就是说第一次和服务器连接并登陆成功后,第二次请求服务器仍然不知道当前请求的用户。Cookie出现就是解决了这个问题,第一次登陆后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当用户第二次返回请求的时候,就会把上次请求存储的cookie数据自动携带给服务器。
- 如果关闭浏览器Cookie失效(Cookie就是保存在内存中)
- 如果关闭浏览器Cookie不失效(Cookie保存在磁盘中)
1、Cookie与Session的区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上,存储在服务器的数据会更加的安全,不容易被窃取。当访问增多,会比较占用你服务器的性能与资源,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。因此使用cookie只能存储一些小量的数据。
2、Token和Session的区别
- session翻译为会话,token翻译为令牌。
- session和session_id:服务器会保存一份,可能保存到缓存/数据库/文件,session_id一般是随机字符串,要到服务器检索id的有效性。Session通过cookie存储session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。
- token:服务器不需要记录任何东西,每次都是一个无状态的请求,每次都是通过解密来验证是否合法。
实现免登录方案
- 首先生成token
- 发送token,两种方式
- 通过
Set-Cookie发送给客户端,用户再次请求时,浏览器会自动将token带上发送给服务器。 - 通过登录API直接将token返回给客户端,客户端通过全局变量/Storage/Cookie等方式存储这个token,当用户再次请求时,客户端将token值存放在请求头的
Authorization中发送给服务器。
- 当token中直接存储了用户信息时,直接解密获取即可;当token只是一个key,真正的数据是存放在Session,Redis 等分布式缓存里时,需要通过token这个key去获取用户信息。从而实现免登陆。
- 为防止token过期,也可以在服务端设置token刷新机制。
