1. 原因
http本身是无状态的,下一次如果还想获取上一次的结果就要加东西,用来标记上一次的连接,这就是session、cookie和token。
session是应用层还是会话层?
抱歉,我不知道,但我认为是会话层,虽然这些信息是放在http报文中的,因为这是基于账户的概念。
2. session
2.1 session的原理
session其实可以理解为一个身份卡,当第一波HTTP连接建立后,服务器会生成一个sessionID给到客户端下次带上就可以了。流程如下:
2.2 session的优缺点
session的缺点很多:
-
这个方法对客户端来说比较简单,本地只需要带上一个字符串就可以,但是对于服务器来说压力会特别大,首先服务器要管理全部的session,这么庞大的数据一般得集群来处理,但是如果原来存储的A机器挂了,就得把数据都扔到B机器上(先不考虑一致性哈希),后来有人提出单独一个集群存储session,大家去那里找,但是这个集群再挂了还是有问题,总之,session在服务器端问题好多。
-
下面这些都是百度的,大多数看不懂
- 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
- 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
- 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
- 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
- 适用接口跨平台: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
- CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
- 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
- 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
- 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)****
2.3 session的发送
cookie:我曾经认为session是cookie的一个字段,然鹅这并不对。浏览器确实会想办法把session传递给服务器,cookie只是其中一个手段,在cookie中会有相应的字段,如果是这种方法可以通过抓包找到。
一般浏览器都是默认开启cookie的,第一次访问服务器,服务器并不知道是因为禁用了cookie还是第一次,所以都会生成sessionid给浏览器,根据下次请求中浏览器是否带着session来判断是不是禁用了cookie
URL重写:具体的方法没多研究,下面是维基百科,写的挺好的,而方法就是把session放在重写的URL后面
最常见的用法,就是将一组URL层次结构字符串,转换成带有查询字符串(query string)的URL,或是反向转换,例如: http://www.somebloghost.com/Blogs/Posts.php?Year=2006&Month=12&Day=10
经过URL重写后,可以变成:
http://www.somebloghost.com/Blogs/2006/12/10/
另一个例子,下面的URL:
http://www.somehost.com/Blogs/2006/12/
经过URL重写后,可转换成:
http://www.somehost.com/Blogs.aspx?year=2006&month=12
因此,用户可以使用较直觉的方式来输入URL(这也是REST的主要目的),是搜索引擎最优化(SEO)的作法之一。而应用程序开发者可以利用这个机制来将参数隐藏起来,可避免让网络上的恶意用户收集到有利于发动攻击的信息。
表单隐藏字段:就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。这种方法以几乎被URL重写的所取代
3.token
token的方法叫做JSON Web Token (JWT) ,就是服务器生成一个随机串,服务器统一用一个哈希方式对其进行机密,把加密后的口令发给客户端,客户端每次上报的时候把这个token在HTTP头中带上就OK了。
这里有很大很大的问题,我查阅了所有的百度和大部分谷歌,都没有说清楚,或许应该去看一下源码。服务器端存储的到底是什么,如果按照有些文章的说法把token存储在redis里,那和存储session有啥区别吗?根本做不到对服务器压力的减少。所说的服务器验证token,到底是怎么验证的?是整个服务器只留一个哈希函数?每次客户发送key和value,由服务器验证?明显不是,token只是一个字符串,所以这里问题很大,也没有文章说的清楚。
下面是token的缺点,可以参考一下
https://medium.com/@rahulgolwalkar/pros-and-cons-in-using-jwt-json-web-tokens-196ac6d41fb4
https://stackoverflow.com/questions/27666810/json-web-token-jwt-advantages-disadvantages-over-cookies
https://blog.csdn.net/weixin_43814195/article/details/84957457
4. cookie
现在发现,cookie的问题不是很大,就服务器端生成的一堆数据,到时候发给服务器。
发送的时候服务器在Set-CooKie中设置要发送的cookie。cookie的格式
Set-Cookie:"name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnyly;secure"
其中name=value是必选项,其它都是可选项。Cookie的主要构成如下:
name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的。
value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码
domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:
yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效).
path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie。
expires:失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差。
max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。
HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置。
secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了服务器端设置
剩下的东西我不是很关心了