cookie,session,token的区别

cookie,session,token它们本质上不是同一个东西。但是都跟维持状态信息有关系

什么是状态信息呢?

我来用一个登录来个大家讲解。

如果我们登录以后,希望后续的所有的页面都维持登录的状态,那我们就需要用刚刚讲到的cookie,session,token来进行实现。

无任何技术:

那么如果没有使用上面的任何一种技术,我们要维持用户的登录状态信息,是非常麻烦的

我给你举个例子,就比如说当发起一个登录请求,把用户名,密码传到服务端。服务端进行鉴权(认证),判断用户名密码是否正确,正确的话需要再把用户名密码传到前端,

以维持登录的状态信息,那么后续请求任何页面,我们都需要带上用户名密码。那么这样做的话毫无疑问,既不安全又麻烦。 

 

使用cookie:

我们就可以用cookie来解决。同样的前端发起登录请求,会在服务端进行用户名密码认证,如果认证成功,会响应用户名到前端,前端把用户名进行保存(到cookie),

保存之后,cookie是保存在浏览器这一端,那么后续就登录成功,后续所有请求都会自动带上cookie,这样就维持了用户的登录状态。

那如果只用cookie来存储状态信息呢?其实是会有很多问题的。

1.安全风险:有被篡改的风险。

2.容量限制:4kb。

3.可用限制:用户可能禁用。

因为cookie是存储在客户端的,也就是存储在浏览器,那用户呢,他是可以去篡改,就像刚刚直接把用户名存储在了cookie,那登录成功之后呢,它每次的请求都会带上cookie,

以证明当前已经登录,那么在服务端呢,就会根据cookie当中的这个用户名,来获取当前的登录信息,那么用户他是可以把当前的cookie当中的用户名给篡改掉,改成其他的用户,

那么对于服务端来说,我只会根据你cookie的信息来获取当前登录的用户,所以一旦被篡改的话,是有非常大的安全风险。

当然可以进行加密,但是一旦用户知道我们的加密规则呢?也是可以进行篡改的。

那么第二个问题就是它的容量有限,默认的大小是4kb,当然也可以通过浏览器进行修改。以及用户他可以通过浏览器把cookie给禁掉。所以不能完全依赖cookie保持这个登录状态。

 cookie+session:

那么进而我们就可以通过session,那么session的使用过程是这样的。

当前端发起登录请求,会把用户名密码传到后端,后端验证,如果认证成功,可以往session当中存入当前用户的信息,然后进行响应,

响应的时候会在响应头里面存入一个叫做set-cookie的属性,然后再把当前session的唯一id放在属性当中,前端会自动在cookie中存入当前的sessionId,那么下次登录成功以后,下一次请求就会自动在请求头

当中设置cookie信息。服务端拿到cookie当中的session id就可以得到当前这次请求所对应的session信息了,那么就可以获取到当前登录的用户信息,以维持当前的登录状态。

那么在这个过程中,session它的使用其实是非常方便的,我们只需要在后端存入当前用户的信息,并且不仅仅限于字符串,我们可以存入整个的User对象,那么下次获取是非常方便的。

那么我们的服务器比如tomcat,它会自动在响应头里面存入set-cookie的属性以及当前session的唯一ID,这个我们不需要去管。然后浏览器发现你的响应头里面有set-cookie属性,它就会自动的存入session id到cookie中。

我们不需要在浏览器这一端在前端去调用setCookie()方法,响应头当中的set-cookie命令它会自动帮我们存储,并且浏览器下一次请求也会把cookie传到服务端,所以整个过程是自动完成,我们只管往session中存数据即可。

用起来是非常方便的。当然session同样有一些问题。

1.占用服务器资源。

2.扩展性差(分布式集群)。

3.依然需要依赖cookie,跨域限制。

 如果在高并发情况下,是会比较占用服务器内存资源的。以及它的扩展性比较差,对跨域的限制,这两点怎么理解呢?比如我们的后端它的压力比较大,此时我们可能就会进行集群部署,假如前端发起登录请求,

我们往session中存入当前的用户信息,只会存在一台服务器,那么其他服务器并没有当前的用户登录信息,那么集群之后负载均衡,有可能下一次的请求就会打到其他的服务器上面,那么就会判定你当前并没有登录。

所以在集群情况下,session它是不支持的,以及呢,我们现在基本都是前后端分离的架构,特别是在移动互联网盛行的情况下,我们还会有移动端H5,还会有小程序,安卓端,苹果端,它们都会有各自的端口域名,

这个时候前端再请求后端就会发生跨域,跨域的情况下,cookie默认是无法进行传递的,我们需要在后端设置允许跨域,还需要在前端单独的去设置,允许跨域的cookie传递,总之呢,跨域进行传递cookie非常麻烦。

所以在集群环境,以及前后端分离的架构下,session已经不再适用

 token:

那么其实我们就可以通过token来进行改造了,token说白了就是一个秘钥字符串。我们怎么去进行加密呢?

其实jwt提供了规范,json web token,说白了就是通过json来进行传递加密后的字符串。

jwt的整个使用过程,同样的前端发起登录请求,后端会进行认证,认证成功之后会创建一个jwt的字符串,它会包含三段信息,然后会把创建好的jwt返回给前端,前端拿到jwt的token如果想要数据的载体,只要进行分割,分割之后

拿到第二段,因为第二段保存的是数据的载体,拿到之后通过base64方式进行解码即可。

那么登录成功之后,后续的请求只需要请求头当中设置一个跟后端约定的一个属性,然后再把响应的jwt的token传入到后端,那么后端拿到这个token就会进行jwt解密,然后验证signature, 如果校验成功信息没有被篡改,

就会放行,正常的进行响应。所以说使用jwt,我们不需要依赖后端的任何存储,也不需要依赖前端的任何存储,它就是一个加密之后的字符串而已,对于我们现在的集群以及前后端分离的架构这样的环境使用起来非常方便。

登录认证历程:

无技术-->cookie-->cookie+session-->token,session共享-->双token。

后者的出现都是为了弥补前者的缺陷。

注意:

jwt无法做到主动退出登录。

虽然我们使用JWT已经很方便了,但是有一个很严重的问题就是,我们没办法像Session那样去踢用户下线,什么意思呢?我们之前可以使用退出登录接口直接退出,用户Session中的验证信息也会被销毁,但是现在是无状态的,用户来管理Token令牌,服务端只认Token是否合法,那这个时候该怎么让用户正确退出登录呢?

jwt有其自己的适用场景,任何时候都不应该首要考虑JWT。你使用JWT的时候,应该是你有明确需要JWT特性的时候。

传统的Token方案,其实就是Session的管理方案。Session管理的方式是什么?无非就是给你一个sessionId,然后服务器向这个SessionId的内存里存放用户当前的登陆信息以及相关数据。

所谓的Redis+token。无非也就是给这个基础业务包了一层壳。Session说是不安全,给你颁发了一个名叫token的玩意。传统session不支持分布式,于是引入了redis。(其实说实话,分布式Session用Redis实现也是这么个道理。

就这么个最传统的token方案,已经足以解决99%的业务场景

单个token+redis+自动续期与双token+redis方案对比:
 

  

 

 

posted @ 2024-04-28 16:38  super超人  阅读(27)  评论(0编辑  收藏  举报