概述:
cookie 验证准确的说是利用 cookie 来作为媒介,存储 session ID 进行验证,下文中提到的 cookie 验证主要是指 session ID 存储到 cookie 中,携带在请求头中进行验证
token 其实也可以借助 cookie 来存储,token 验证主要是指 token 存储到 localStorage / sessionStorage / cookie 中,携带在请求头中的 Authorization 进行验证。
首先明确http是无状态的:它就像一个机器一样,只知道机械地运转,但无法区分是谁在控制它,是谁在请求它,通过这两种验证方式可以让 http 分辨出哪些是可信任的。
session
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。
本来 session 是一个抽象概念,开发者为了实现中断和继续等操作,将 user agent 和 server 之间一对一的交互,抽象为“会话”,进而衍生出“会话状态”,也就是 session 的概念。
而我们今天常说的 “session”,是为了绕开 cookie 的各种限制,通常借助 cookie 本身和后端存储实现的,一种更高级的会话状态实现。
cookie
cookie本质上是实现了session,通过建立客户端和服务端的会话,客户端和服务端都保存session ID,这样做每次请求时,服务端都要去数据库中找一下是否有这个人。
cookie 是一个实际存在的东西,http 协议中定义在 header 中的字段。可以认为是 session 的一种后端无状态实现。
假如我们要去迪士尼玩耍,cookie机制就相当于,我们去之前,需要在网上提前买好票,这样我们进园时,保安手里就有一份买了票的人员名单,他需要在每个人进园的时候,在这份名单里查找一下有没有这个人,如果有,那你就可以进去,否则,你就得即刻买票。
过程:
- 客户端发送账号和密码(可用
window.btoa()
转码密码); - 服务端接收后,在数据库里找一下有没有这个账号和密码,如果没有找到的话,就创建一个 session,存入数据库,并把
session ID
放进 cookie 中,返回给客户端; - 客户端收到后,把 session ID 存起来,每次发起其他请求,都带上这个
session ID
放在请求头中; - 服务端收到后,在数据库中查找
session ID
对应的 session,如果找到了,说明这个用户就通过了验证,服务端就认识了,返回相应的数据。 - 一旦用户登出,则 session 在客户端和服务器端都被销毁。
ajax请求携带cookie和自定义请求头header(跨域和同域):
- 同域请求下,ajax会自动带上同源的cookie;
- 跨域请求下,ajax不会自动携带同源的cookie,需要通过前端配置相应参数才可以跨域携带同源cookie,后台配置相应参数才可以跨域返回同源cookie;
前端参数:withCredentials: true
后台参数:Access-Control-Allow-Origin:
和Access-Control-Allow-Credentials:
配置了
Access-Control-Allow-Credentials:true
则不能设置Access-Control-Allow-Origin:*
session 和 cookie 的区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
token
token 则不需要建立 session,不建立会话,而是通过携带“令牌”,告诉服务端“我是你的同事”,我可以要求你做一些事情。
token 放在了 请求头
中的 Authorization,形式是 Bearer { JWT },但是也可以在 post body 里发送,甚至作为 query parameter。
过程:
- 客户端发送账号和密码(可用
window.btoa()
转码密码); - 服务端接收后,生成一个 token,返回给客户端,但自己不保存;
- 客户端收到后,把 token 存起来,大多数通常在
local storage
,但是也可以存储在session storage
或者cookie
中,每次操作都带上这个 token; - 客户端又发起其他请求,将 token 放进请求头中的
Authorization
; - 服务器端解码 JWT 然后验证 token,如果 token 有效,说明这个用户就通过了验证,服务端就认识了,返回相应的数据。
同样去迪士尼玩耍,token机制就相当于,我们去之前,需要在网上提前买好票,然后我们拿到一份对应的二维码,这样我们进园时,直接扫二维码,成功可以进去,否则,你就得即刻买票。
不需要保安找我们的名字,实现了智能化,也就是无状态。
ajax添加Token到Header中的方法:
$.ajax({
type: "GET",
url: "/access/logout/" + userCode,
headers: {'Authorization': token}
})
$.ajax({
type: "GET",
url: "/access/logout/" + userCode,
beforeSend: function(request) {
request.setRequestHeader("Authorization", token);
},
success: function(result){}
})
token 相对 cookie 的优势
- 支持跨域访问 ,将token置于请求头中,而cookie是不支持跨域访问的;
- 无状态化, 服务端无需存储token ,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;
- 无需绑定到一个特殊的身份验证 方案(传统的用户名密码登陆),只需要生成的token是符合我们预期设定的即可;
- 更适用于移动端 (Android,iOS,小程序等等),像这种原生平台不支持cookie,比如说微信小程序,每一次请求都是一次会话,当然我们可以每次去手动为他添加cookie;
- 避免CSRF跨站伪造攻击 ,还是因为不依赖cookie;
- 非常适用于RESTful API ,这样可以轻易与各种后端(java,.net,python…)相结合,去耦合
参考:https://www.jianshu.com/p/c33f5777c2eb