Open brunoyang opened 8 years ago
http是无状态的,你不能通过观察一条http请求来猜想前一条或后一条请求可能的样子。这为网站管理登录用户带来了困难,因为无状态,所以你无法知道这条请求从何而来。在1994年时,网景浏览器弄出了可以存储在用户本地的一小段文本信息,被称为cookie。
这个名字还有一段小故事,美国有一款叫Fortune cookie的饼干,里面藏有一张写着有趣句子的纸条。网景借鉴了这个寓意,把http内的隐藏信息称为cookie。
用户在访问某个网站时,服务器的响应头里会带有Set-Cookie字段,告诉浏览器存储这里面的信息,于是用户的浏览器里就带有cookie了,发第二条请求时就会带上Set-Cookie字段里的值,这就是客户端能做的所有。
这时来了个产品经理,说我们网站要支持登录。所谓登录,就是用户带上凭证,server允许其进行不带凭证的用户不能进行的操作。用户登录后,server在response里加上Set-Cookie字段,并在server里(内存/文件/数据库)存储该值。下一次用户再发来请求,就会带上cookie,然后server取出cookie与存储内的值作对比,若匹配,我们就会认为改用户是已登录的,从而放行操作。以上的行为,就可以称为维持了一段会话(session)。
这时产品经理说,我们网站要支持20分钟超时登出。也就是说如果用户20分钟内没有发来任何请求,我们就认为用户死了,也就没有维持这段会话的必要了,可以删除掉存储的cookie值了。但在未过期之前,用户每发来一个请求,就给该用户 +20m。
永不满足的产品经理说,我们网站要提高安全性,不管你们干嘛,就是要提高安全性。经过一番安全检查,我们发现我们的cookie有被篡改的风险。针对这种情况,我们可以给cookie加签。我们选择把cookie增加个时间戳字段,然后进行加密后提取摘要,再把这个摘要值放在cookie和server的存储中。在下一次请求时,我们就会对比这两个值是否相等,若相等,重新更新时间戳并计算,保证每条请求都是独一无二的;若不相等,说明该cookie被篡改。
后来,产品经理说,我们要支持单点登录。后来他坟头草两丈高了吧。
上面说了这么多,我们再结合代码来看看,下面是根据 koa-generic-session@2.10.2做的源码解读。
来看/lib/session.js。
const session = require('koa-generic-session'); const app = require('koa')(); app.use(session());
这是最基本的用法,session可以传入配置项,如下:
{ key, // session id的键名 store, // 如何存储session,一般会选择redis。 // 若不传入,会默认存储在内存中,在生产环境下会产生一个警告 ttl, // session过期时间 prefix, // 存储sessoin时的前缀 cookie, // cookie配置项 defer, // 默认情况下,每次app.use(session());后都会去生成存储session,但静态文件是不需要session的。 // 所该选项为true,调用yield this.session;才会去生成session。 genSid, // 可以自定义生成session的方法 errorHanlder, // 自定义处理session存储和取出失败时的错误处理 valid, // 自定义校验session, beforeSave, // 钩子函数 sessionIdStore, // object,内部需要有set,get,reset三个方法用来往ctx.cookies上设置cookie }
选项中有个defer字段,作用如下
return options.defer ? deferSession : session;
在设置defer为true后只有在调用yield this.session时才会生成session,节省资源。我们来看deferSession函数。
yield this.session
deferSession
代码太长,只挑要紧的讲。在这个函数内有getter/setter,和regenerateSession方法。getter方法取得session,若已被setter方法设置过,就直接返回设置的session。若没设置过,会调用getSession获取session。
regenerateSession
getSession的流程就是先检查sessionId(cookie中),若没有说明是新连接,调用generateSession生成session,若不是,则从存储中取出的对应的session(可能为空,因为访问间隔超过超时时间),随后返回一个object。
在做完上面的步骤后,就会调用refreshSession,当session变为空,就从存储中删掉该条session,若发生改变,则更新cookie和存储中的值。
session方法就是deferSession的简化版,就不重复了。
session
koa-generic-session 和 koa-csrf 配合是发生 令牌丢失错误,请问下这个从哪方面开始着手查看这个错误呢。
能贴下具体的报错信息吗
产品经理之死
http是无状态的,你不能通过观察一条http请求来猜想前一条或后一条请求可能的样子。这为网站管理登录用户带来了困难,因为无状态,所以你无法知道这条请求从何而来。在1994年时,网景浏览器弄出了可以存储在用户本地的一小段文本信息,被称为cookie。
这个名字还有一段小故事,美国有一款叫Fortune cookie的饼干,里面藏有一张写着有趣句子的纸条。网景借鉴了这个寓意,把http内的隐藏信息称为cookie。
用户在访问某个网站时,服务器的响应头里会带有Set-Cookie字段,告诉浏览器存储这里面的信息,于是用户的浏览器里就带有cookie了,发第二条请求时就会带上Set-Cookie字段里的值,这就是客户端能做的所有。
这时来了个产品经理,说我们网站要支持登录。所谓登录,就是用户带上凭证,server允许其进行不带凭证的用户不能进行的操作。用户登录后,server在response里加上Set-Cookie字段,并在server里(内存/文件/数据库)存储该值。下一次用户再发来请求,就会带上cookie,然后server取出cookie与存储内的值作对比,若匹配,我们就会认为改用户是已登录的,从而放行操作。以上的行为,就可以称为维持了一段会话(session)。
这时产品经理说,我们网站要支持20分钟超时登出。也就是说如果用户20分钟内没有发来任何请求,我们就认为用户死了,也就没有维持这段会话的必要了,可以删除掉存储的cookie值了。但在未过期之前,用户每发来一个请求,就给该用户 +20m。
永不满足的产品经理说,我们网站要提高安全性,不管你们干嘛,就是要提高安全性。经过一番安全检查,我们发现我们的cookie有被篡改的风险。针对这种情况,我们可以给cookie加签。我们选择把cookie增加个时间戳字段,然后进行加密后提取摘要,再把这个摘要值放在cookie和server的存储中。在下一次请求时,我们就会对比这两个值是否相等,若相等,重新更新时间戳并计算,保证每条请求都是独一无二的;若不相等,说明该cookie被篡改。
后来,产品经理说,我们要支持单点登录。后来他坟头草两丈高了吧。
koa-generic-session
上面说了这么多,我们再结合代码来看看,下面是根据 koa-generic-session@2.10.2做的源码解读。
来看/lib/session.js。
这是最基本的用法,session可以传入配置项,如下:
选项中有个defer字段,作用如下
在设置defer为true后只有在调用
yield this.session
时才会生成session,节省资源。我们来看deferSession
函数。代码太长,只挑要紧的讲。在这个函数内有getter/setter,和
regenerateSession
方法。getter方法取得session,若已被setter方法设置过,就直接返回设置的session。若没设置过,会调用getSession获取session。getSession的流程就是先检查sessionId(cookie中),若没有说明是新连接,调用generateSession生成session,若不是,则从存储中取出的对应的session(可能为空,因为访问间隔超过超时时间),随后返回一个object。
在做完上面的步骤后,就会调用refreshSession,当session变为空,就从存储中删掉该条session,若发生改变,则更新cookie和存储中的值。
session
方法就是deferSession
的简化版,就不重复了。