1、用户验证发展史
1.1 最初的web
最开始的web基本上都是文档浏览,不需要记录谁在那一段时间浏览了什么文档,每次请求都是一个新的http协议,就是请求加响应,服务器不知道是谁刚刚发来的http请求,每个请求都是全新的。
1.2 交互式web兴起
随着交互式web应用的兴起,像在线购物网站,需要登录的网站等待,就面临了一个问题,那就是要管理会话,必须记住那些人登录系统,那些人将商品添加到购物车,也就是说服务器必须将每个用户的请求区分开。
所以想出了一个办法,给所有用户发一个会话标识**(session id)**,说白了就是一个随机的字符串,每个用户收到的字符串都不相同,每次用户向服务器发起http请求都要把这个字符串一起发送过来,这样服务器就能区分开每个用户了。
1.3 服务器蚌埠住了
给用户发送会话标识的方法,每个用户只需要保存自己的session id,但是服务器需要保存所有用户的session id。如果用户太多了,成千上万,甚至几十万,那服务器就蚌埠住了呀。
这对服务器来说是个巨大的开销,严重限制了服务器扩展功能。
1.4 早期的负载均衡
为了解决这个问题,可以采用多台服务器作为一个集群,一起分担请求压力,也就是最早期的负载均衡。
-
但是,存在一个问题。
-
问题:
- 如果用两个服务器组成一个集群,小F通过服务器A登录了系统,那session id会保存在服务器A上,假设小F下一次请求被转发到服务器B怎么办?服务器B可没有小F的session id。
-
第一次解决:
-
虽然可以让小F的请求一直粘连在服务器A上,但要是A挂掉了,还得去服务器B。
-
所以只好所session的复制,把session id在两个服务器之间复制,消耗服务器性能。
-
-
第二次解决:
- Mencached:将session id集中存储到一个地方,所有服务器收到请求都访问这个地方的数据,这样就不用服务器间对session进行复制了,但是增加了单点失败的可能性,要是负责session的服务器挂掉了,所有用户都得重新登录,蚌埠住了。
1.5 token出现
-
思考:为什么要服务器保存session呢?让客户端自己保存多好?
-
问题:
- 如果不保存session id怎么确认客户端发给我得session id是我生成的呢?
- 如果不验证,怎么知道他们是不是合法登录的用户,万一是伪造的session id怎么办?
-
Ⅰ方案:
- 用户登录时服务器发个令牌(token),里面包含登录用户的user id,下次该用户再次通过http请求访问服务器的时候,把这个token通过http header带过来就可以了
-
Ⅰ方案问题:
- 这个session id没有本质区别,任何人都可以伪造,所以得想点办法,让别人伪造不了。
-
Ⅱ方案:
- 做个签名,用HS256算法+密钥对数据做个签名,把签名和数据一起作为token,由于密钥别人不知道,那么就无法伪造token了。
- 这个token服务器不保存,再下一次用户把token发过来得时候,我在用同样的HS256算法和同样的密钥对数据进行一次签名,和token中的签名做个比较,如果相同,那么就可以判断用户已经登录过了,并且可以直接取到用户的user id,如果不想同,数据部分肯定被人篡改过了,就返回信息告诉发送者:狗贼,还想盗我号!
-
优化:
- token中的数据是明文保存的,还是可以被别人看见,所以不能保存密码这样的敏感信息。
-
存在问题:
- 如果用户的token被嫖了,那么服务器也没办法,在白嫖者访问时服务器会认为这个人是合法用户,这其实和用户session id被盗取了是一样的
-
总结:
- 这样一来,服务器不用保存session id了,只生成token,然后验证token,用CPU计算时间获取用户session存储空间。
- 解除了session id这个负担,服务器集群可以轻松的做水平扩展,用户访问量增加,直接加服务器就行了。
2、Cookie
cookie是一个非常具体的东西,指的是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
cookie由服务器生成,发送给浏览器,浏览器会把cookie以key-value的形式保存到某个目录下的文本文件内,下次请求同一网站时会把该cookie一起发送给服务器。
cookie只存在于客户端,它不会占用太多磁盘空间,所以每个域的cookie数量是有限的。
3、Session
session本质是区分身份。
为了区分用户身份,服务器要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道请求来自于谁了。
客户端保存“身份标识”方式很多,对于浏览器客户端,默认采用cookie的方式保存。
- 优点:
- 服务器使用session把用户的信息临时保存到服务器上,用户离开网站后session会被销毁。
- 这种用户信息存储方式相对于cookie更安全
- 缺陷:
- 如果web服务器做了负载均衡,那么下一次请求操作到了另一台服务器,session会丢失,需要用户重新登录。
4、token
4.1 token特性
- 无状态、可扩展
- 支持移动设备
- 跨程序调用
- 安全
4.2 token起源
在token之前,程序都是通过在服务端存储的登录信息来判别请求的,这种方式一般都是通过存储session来完成。随着移动端的兴起,这种验证方式逐渐暴露出了问题,尤其是可扩展性方面。
基于服务器验证方式问题
session
每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发起请求时,内存的开销会不断增大。
可扩展性
在服务端的内存中使用session存储登录信息,伴随而来的时可扩展性问题,例如单台服务器请求上线,设置服务器集群,但容易造成session丢失。
CORS(跨域资源共享)
当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就会出现禁止请求的情况。
CSRF(跨域请求伪造)
用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够利用其访问其他的网站。
4.3 token的验证优势
token的身份验证时无状态的,不需要将用户信息存在服务器或session中。
no session意味着你的程序可以根据需求去增减机器,而不用担心用户是否登录。
4.4 token身份验证过程
-
1.用户通过用户名和密码发送请求
-
2.程序验证
-
3.程序返回一个签名的token给客户端
-
4.客户端存储token,并且用于每次发送请求
-
服务端验证token并返回数据
每次请求都要需要token。token应该在http的头部发送,从而确保http请求无状态。
4.5实现思路
- 1.用户登录校验,校验成功后就返回token给客户
- 2.客户端收到数据后保存在客户端
- 3.客户端每次访问API时携带token到服务器端
- 服务器端采用filter过滤器校验,校验成功则返回请求数据,校验失败则返回错误码
5、refresh_token
5.1refresh_token由来
普通的token方案 有效期设置过长不安全,过短需要频繁重新登录,体验差。
access token 有效期短 被盗损失更小 安全性更高
如果refresh token被盗了 想刷新access token的话 也需要提供过期的access token 盗取难度增加
同时refresh token只有在第一次获取和刷新access token时才会在网络中传输。被盗的风险远小于access token 从而在一定程度上 更安全了一点。 所谓的更安全就是让盗取信息者更不容易获得而已。
5.2 refresh_token机制流程
参考:
- https://www.cnblogs.com/moyand/p/9047978.html
- https://www.jianshu.com/p/f73eec9d1096