此文档非原创,仅作记录
原创地址:https://blog.csdn.net/wtf0712/article/details/92840179 、https://blog.csdn.net/wnvalentin/article/details/89854980
一、鉴权
鉴权是指验证用户是否拥有访问系统的权利—鉴定权限
二、cookie、session和token
为什么会有cookie、session和token?
1、 http是无状态协议
什么是无状态呢?
答:当前请求和上一次或者下一次请求是没有任何关系的,好处是速度快,坏处是无法共享信息。
2、 互联网的兴起
以前的网站,基本用来查看些文件或者图片,作为服务器不需要记录谁来放访问了什么文件,每次来一个新的HTTP请求, 给予响应即可。
但随着互联网的飞速发展, http无状态的缺点被放大。
各种各样的交互网站,必须登录后才能进行一些操作,比如发帖需要记录发帖人、浏览记录等,不同账号访问的信息必须独立存储。
3、 cookie、session的加入
我们不能修改HTTP协议(无状态),那么要解决共享信息的问题必须用其他的手段。
于是就有了会话ID(session id),服务器为每个用户生成一个不一样的随机字符串(session id),一份存在服务器,一份以cookie的形式写给浏览器。浏览器每次向服务器发起HTTP请求时,携带这个字符串(session id)回传给服务器,这样就能区分谁是谁了。
4、 session有啥缺点呢?
虽然session解决了共享信息的问题,但同时对服务器带来了其他问题—资源开销(内存、cpu)。
对于浏览器来说sessionid是非常好用的,只需要在cookie中存一个字符串就行了,但是服务器必须存储所有在线的用户sessionid,那么同时在线的人数越多开销越大,严重影响了服务器的性能。
这时可以选择去扩展服务器做集群(新增多个服务器A,B来分布存储sessionid),但同时也出现分布式sessionid问题,那么可以采用session粘滞(就是让客户端的请求一直粘连在指定的服务器A上, 但是这也不管用, 要是机器A挂掉了, 还得转到机器B去)
那只好做session 的复制了, 把session id 在两个机器之间搬来搬去, 快累死了
后来有个叫Memcached的支了招: 把session id 集中存储到一个地方, 所有的机器都来访问这个地方的数据, 这样一来,就不用复制了, 但是增加了单点失败的可能性, 要是那个负责session 的机器挂了, 所有人都得重新登录一遍, 估计得被人骂死。
也尝试把这个单点的机器也搞出集群,增加可靠性, 但不管如何, 这小小的session 对我来说是一个沉重的负担
5、 摆脱session,拥抱token
上述的解决方案都是围绕session,那么能不能不用sessionid来解决呢?
于是有人就一直在思考, 我为什么要保存这可恶的session呢, 只让每个客户端去保存该多好?
可是如果不保存这些session id , 怎么验证客户端发给我的session id 的确是我生成的呢? 如果不去验证,我们都不知道他们是不是合法登录的用户, 那些不怀好意的家伙们就可以伪造session id , 为所欲为了。
嗯,对了,关键点就是验证 !(服务器只验证不存储)
比如说, 小F已经登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来不就可以了。
不过这和session id没有本质区别啊, 任何人都可以可以伪造, 所以我得想点儿办法, 让别人伪造不了。
那就对数据做一个签名吧, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了。
这个token 我不保存,当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证。
Token 中的数据是明文保存的(虽然我会用Base64做下编码, 但那不是加密), 还是可以被别人看到的, 所以我不能在其中保存像密码这样的敏感信息。
当然, 如果一个人的token 被别人偷走了, 那我也没办法, 我也会认为小偷就是合法用户, 这其实和一个人的session id 被别人偷走是一样的。
这样一来,我就不保存session id 了,我只是生成token , 然后验证token,我用我的CPU计算时间换取了我的session 存储空间 !
解除了session id这个负担,可以说是无事一身轻,我的机器集群现在可以轻松地做水平扩展,用户访问量增大,直接加机器就行。这种无状态的感觉实在是太好了!
cookie、session的区别
cookie:客户端和服务端都能创建cookie,都是存放在客户端。存放一些小而不敏感的数据,并且数据类型只能是字符串(json)。
session:服务端生成session,存放在服务端。可以存放任意数据,java中session中可以存放任意对象。
session必须依赖cookie实现
session和token的区别
session:服务器生成、存储、验证,以cookie的方式传给客户端,客户端以同样方式发送给服务端。
session有状态。
token:服务器生成、验证,以cookie或者请求头的方式传给客户端,客户端以同样方式发送给服务端。
token无状态
token的优势:
(1)无状态、可扩展
在客户端存储的 token 是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载均衡服务器 能够将用户的请求传递到任何一台服务器上,因为服务器与用户信息没有关联。相反在传统方式中,我们必须将请求发送到一台存储了该用户 session 的服务器上(称为Session亲和性),因此当用户量大时,可能会造成 一些拥堵。使用 token 完美解决了此问题。
(2)安全性
请求中发送 token 而不是 cookie,这能够防止 CSRF(跨站请求伪造) 攻击。即使在客户端使用 cookie 存储 token,cookie 也仅仅是一个存储机制而不是用于认证。另外,由于没有 session,让我们少我们不必再进行基于 session 的操作。
Token 是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过 token revocataion可以使一个特定的 token 或是一组有相同认证的 token 无效。
(3)可扩展性
使用 Tokens 能够与其它应用共享权限。例如,能将一个博客帐号和自己的QQ号关联起来。当通过一个 第三方平台登录QQ时,我们可以将一个博客发到QQ平台中。
使用 token,可以给第三方应用程序提供自定义的权限限制。当用户想让一个第三方应用程序访问它们的数据时,我们可以通过建立自己的API,给出具有特殊权限的tokens。
(4)多平台与跨域
我们已经讨论了CORS (跨域资源共享)。当我们的应用和服务不断扩大的时候,我们可能需要通过多种不同平台或其他应用来接入我们的服务。
可以让我们的API只提供数据,我们也可以从CDN提供服务(Having our API just serve data, we can also make the design choice to serve assets from a CDN.)。 在为我们的应用程序做了如下简单的配置之后,就可以消除 CORS 带来的问题。只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。
接口鉴权token解决方案:完成登录之后,获取到token字符串,再次请求时加入。
接口鉴权session解决方案:完成登录之后,获取带有session信息的cookie,再次请求时加入。