目的:解决用户登录状态
从一个简单的登录开始说起,
在我们访问bilibili的时候,第一次需要登录,但后续就不需要登录了,可以直接访问bilibili。
而且每次在页面请求服务器的资源都需要维持登录状态,如果没有使用任何一种技术(cookie,session,token),则需要我们每次请求的时候,都需要将账号密码包含在请求中,这种方式,既不安全,也很麻烦。
那有没有什么好的解决办法呢?
这时候cookie出现了,cookie在客户端-服务器之间的流程如下:
也就是使用了cookie后,用户在第一次成功登录后,服务器会将用户的信息响应到客户端中,客户端(浏览器)会将用户信息保存到cookie中,也就是在客户端中保存了用户信息。那么在之后的每次访问服务器过程中,客户端(浏览器)会自动将cookie的内容包含在请求头(request header)中,如此便维持了用户的登录状态。
但这种方式会有很多的问题:
-
不安全,用户信息存储在客户端,客户可以修改信息
-
容量有限,默认4kb
-
用户可以禁用cookie
于是,session技术出来了,不同于cookie把内容存储在客户端,session把内容信息存储在服务器端。
在用户成功登录后,服务器会生成一个sessionID,并将sessionID响应到客户端中,客户端自动将sessionID保存在浏览器的cookie中。
后续用户的访问,也会自动将sessionID包含在请求头中,服务器判断sessionID是否存在,存在则表明用户已登录,即维持登录状态。而且整个过程是自动完成的,程序员只需要往session中存数据即可,使用起来十分方便。
同样,session优缺点如下:
优点:
-
安全性高,相比较cookie将用户信息存储在客户端,session将用户信息存储在服务器端,因此安全性较高
-
容量大,可以保存对象
缺点:
-
占用服务器资源,由于session容量大,因此在高并发过程中十分占用服务器资源
-
扩展性差
-
跨域限制
在分布式场景中,会有多台服务器,用户登录会在其中一台服务器中生成sessionID,而其他服务器没有sessionID,如果用户的下一次请求被分发到其他服务器中,则会误判用户没有登录。
而且在目前后端分离的大环境中,会有多个前端(web,小程序,h5,安卓端,ios端),每个端都会有各自的域名端口,这个时候,前端请求后端会有跨域,跨域情况下,cookie默认是无法传递的,而sessionID本质上还是使用了cookie,也会被限制。因此需要前端单独去设置cookie允许跨域传递。
因此,在前后端的背景下,session也不再适用,于是token技术出现了。
token其实就是一个字符串,而JWT(Json Web Token)对token进行了一个规范。
Jwt由以点(.)分隔的三个部分组成,它们是:
-
Header
-
Payload
-
Signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
其形式为xxxx.xxxx.xxxx
并且可以将其解析为三个部分
Header 由Token的类型(JWT)和所使用的签名算法(HMAC SHA265)组成
Payload为有效负载,其中包含你要放的数据内容。
Signature,这部分是一个签名,是对Header和Payload数据签名,确保上面的内容不被篡改。
JWT的认证流程:
用户在登录成功后,服务器会生成一个JWT,然后将token响应到客户端,存放到request header中,之后的每次请求会带上token,服务器接收到token会解密,检查signature是否被篡改。
优点:
-
适用于前后端分离场景和分布式项目
-
解决了session和coookie面临的跨域和存储压力问题
缺点:
-
JWT默认不加密,因此会导致数据泄密,但可以将原始令牌加密,来传输私密信息。