cookie、session、token为了解决什么问题:
HTTP是一种无状态的协议,而服务器的业务必须是有状态的。
随着在线购物网站、需要登录的网站等等,面临的问题就是要管理会话。Session 、 Cookie、Token等就是来解决这个问题的机制。
鉴权流程图:
根据上图可以看到,从用户请求发起,到服务端完成操作,流程颇多,但是HTTP无状态,我们如何才能详细记录这些操作过程并加以严格的权限判断控制,接下来就开始今天的主题!
Cookie 诞生的最初目的是为了存储 web中的状态信息,方便服务器端使用。比如判断用户是否是第一次访问网站等问题。
cookie是保存在本地终端的数据。cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
Cookie干嘛用的?Cookie存在的价值
session从字面上讲,就是会话。这个就类似你和一个人交谈,你怎么知道当时和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他是张三;
session也是类似的道理,服务器要知道当前请求发给自己的是谁。为了做这种区分,服务器就是要给每个客户端分配不同的"身份标识"(session id),然后客户端每次向服务器发请求的时候,都带上这个”身份标识“,服务器就知道这个请求来自与谁了。
至于客户端怎么保存这个”身份标识“,可以有很多方式,对于浏览器客户端,大家都采用cookie的方式。
session是服务端存储的一个对象,主要用来存储所有访问过该服务端的客户端的用户信息(也可以存储其他信息),从而实现保持用户会话状态。但是服务器重启时,内存会被销毁,存储的用户信息也就消失了。
不同的用户访问服务端的时候会在session对象中存储键值对,“键”用来存储开启这个用户信息的“钥匙”,在登录成功后,“钥匙”通过cookie返回给客户端,客户端存储为sessionId记录在cookie中。当客户端再次访问时,会默认携带cookie中的sessionId来实现会话机制。
理解一:
浏览器第一次访问服务器,服务器会创建一个 session,并生成一个 sessionId
将 sessionid 及对应的 session 分别作为 key 和 value 保存到缓存中,也可以持久化到数据库中
服务器再把 sessionid,以 cookie 的形式发送给客户端
浏览器下次再访问时,会直接带着 cookie 中的 sessionid。然后服务器根据 sessionid 找到对应的 session 进行匹配
存在的问题----扩展性不好:
单机没有问题,但如果是服务器集群,或者是跨域的服务导向架构,就要求session数据共享,每台服务器都能够读取session。
另一种方案是服务器索性不保存session数据了,所有数据就保存在客户端,每次请求都发回服务器。
思考一下:服务器为什么要保存可恶的session,为什么不让每个客户端去保存。
但是如果不保存session id,怎么验证客户端发给服务器的session id的确是服务器生成的。
如果不去验证,服务器不知道客户端是不是合法登录的用户,就会有人伪造session id,为所欲为。
关键点是验证。
比如说,小F已经登录了系统,服务器给客户端发一个令牌(token),里面包含了小F的user id,下一次小F再次通过http 请求访问服务器的时候,客户端把token通过http header带给服务器。
不过要是这样的话,就和session id没有区别,任何人都可以伪造。
服务器可以对数据进行签名,eg:用HMAC-SHA256 算法,加上一个只有服务器才知道的密钥,对数据做一个签名,把签名和数据一起作为token,由于密钥其他人不知道,就无法伪造token。
这个token 我不保存, 当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证。
token中的数据是明文保存的,还是可以被别人看到的,但所以我不能在其中保存像密码这样的敏感信息。
当然, 如果一个人的token 被别人偷走了, 那我也没办法, 我也会认为小偷就是合法用户, 这其实和一个人的session id 被别人偷走是一样的。
这样一来, 我就不保存session id 了, 我只是生成token , 然后验证token , 我用我的CPU计算时间获取了我的session 存储空间 !
解除了session id这个负担, 可以说是无事一身轻, 我的机器集群现在可以轻松地做水平扩展, 用户访问量增大, 直接加机器就行。 这种无状态的感觉实在是太好了!
token的意思是“令牌”,是用户身份的验证方式,最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接token请求服务器)。还可以把不变的参数也放进token,避免多次查库。
token和session的区别:
Session是一种HTTP储存机制, 为无状态的HTTP提供持久机制;
Token就是令牌, 比如你授权(登录)一个程序时,它就是个依据,判断你是否已经授权该软件;
Session和Token并不矛盾,作为身份认证Token安全性比Session好,因为每一个请求都有签名还能防止监听以及重放攻击,而Session就必须依赖链路层来保障通讯安全了。如上所说,如果你需要实现有状态的回话,仍然可以增加Session来在服务端保存一些状态。