相信每一个做过web开发的人,都或多或少用过或者听说过session、cookie,以及token以及JWT。有时候感觉很困惑,仿佛都是差不多的东西,这里就简单的对这几个概念做一个阐述。
首先必须要知道的是:
http协议是无状态的
什么是无状态呢?就是说这一次请求和上一次请求是没有任何关系,互不相识的。这种无状态的好处是快速,而坏处可想而知:用户发起登陆请求,成功后,发起另一个页面跳转请求,但因为无状态,服务器并不知道这个用户是不是已经登录过了,因此就只能再把这个请求重定向到登陆页面。
这样用户就疯了,破系统怎么一直让我登录。
session和cookie
所以,前辈们就想了一个办法,在第一次登录后,在服务器端产生一个会话id(sessionId),记录一下用户及其状态。然后把sessionId返回给浏览器。浏览器将这个sessionId记录到cookie里,之后的请求再把它带上。这样服务器从请求中拿到cookie里的sessionId,然后到自己的存储(一般是用redis)里查一下,得到用户的状态。接下来就可以畅通无阻了。
总之,
session是服务器端,cookie是浏览器端(用户端)
cookie只是实现session的其中一种方案。虽然是最常用的,但并不是唯一的方法。禁用cookie后还有其他方法存储,比如放在url中
现在大多都是Session + Cookie,但是只用session不用cookie,或是只用cookie,不用session在理论上都可以保持会话状态。可是实际中因为多种原因,一般不会单独使用
用session只需要在客户端保存一个id,实际上大量数据都是保存在服务端。如果全部用cookie,数据量大的时候客户端是没有那么多空间。
如果只用cookie不用session,那么账户信息全部保存在客户端,一旦被劫持,全部信息都会泄露。并且客户端数据量变大,网络传输的数据量也会变大
如果后端服务是分布式部署,session一般统一放在redis集群中。这样有个问题就是一旦redis故障,可能会影响所有的用户请求。
小结
简而言之, session 有如用户信息档案表, 里面包含了用户的认证信息和登录状态等信息. 而 cookie 就是用户通行证
所以,在后台进行session的存储和运维这件事是非常重要和危险的,对可靠性的要求极其高。
那么,我们有没有可能不存储session呢?
token
其实是可以的。这样来一步步思考:
如果我们把所有信息全部放在cookie里,那么只要cookie将用户的id和状态给服务器传过去就可以了。
但是这样非常危险。用户可以随意伪造cookie,并且也容易被劫持
所以,问题变成了,怎么确保安全性?
答案就是做签名。在用户第一次登录时,服务端使用例如SHA256的算法对数据行加密。得到的加密结果,就称之为token。
之后每一次请求,浏览器都把加密后的token带过来,服务器再使用相同的算法对数据进行一次加密,比较两次加密的结果,相等即为验证通过。
因为私钥只有服务器知道。所以用户过来的请求是无法伪造的。
这样一来,服务器不需要再费力的保存session数据。即使流量大增,只要增加服务器即可。
token的优势:
无状态、可扩展
支持移动设备(移动设备是没有cookie的)
跨程序调用
安全
JWT
既然token这么好,那我们怎么更加方便的使用呢?
JWT全称是JSON Web Token。是token的一种解决方案,从名字可以看出是使用JSON格式传输token
JWT 由 3 部分构成:
Header :描述 JWT 的元数据。定义了生成签名的算法以及 Token 的类型。
Payload(负载):用来存放实际需要传递的数据
Signature(签名):服务器通过Payload、Header和一个密钥(secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
流程:
在基于 Token 进行身份验证的的应用程序中,用户首次成功登录后,服务器通过Payload、Header和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端,
客户端将收到的 Token 保存在 Cookie 或者 localStorage 中,之后客户端发出的所有请求都会携带这个令牌。而为了能顺利实现跨域跨域,建议最好把它放在 HTTP Header 的 Authorization字段中:Authorization: 你的Token。
总结
session存储于服务器,可以理解为一个状态列表,拥有一个唯一识别符号sessionId,通常存放于cookie中。服务器收到cookie后解析出sessionId,再去session列表中查找,才能找到相应session。依赖cookie
cookie类似一个令牌,装有sessionId,存储在客户端,浏览器通常会自动添加。
token也类似一个令牌,无状态,用户信息都被加密到token中,服务器收到token后解密就可知道是哪个用户。需要开发者手动添加。
jwt只是一个跨域认证的方案
补充:
JWT 与 Oauth2.0
Oauth 2.0 是一种授权机制,用来授权第三方应用,获取用户数据,它与 JWT 其实并不是一个层面的东西。Oauth2.0 是一个方便的第三方授权规范,而 JWT 是一个 token 结构规范。只是 JWT 常用来登陆鉴权,而 Oauth2.0 在授权时也涉及到了登陆,所以就比较容易搞混。
如果看懂了,给个赞吗?比心