标签:return 验证 签名 signed 发送 final 其他 alt 匿名函数
├── lib
│ ├── context.js
│ ├── session.js
│ └── util.js
├── index.js
└── package.json
const json = session.toJSON()
------用户数据
koa-session 的 Session类的实例-----session对象,用来操作 用户数据(用户数据的载体)
koa-session 中的 session对象不等于用户数据,koa-session 会给 session对象中添加其他字段,用于判断有效期
空session(新session),不包含用户数据
// do nothing if 【new】 and not populated const json = session.toJSON(); if (!prevHash && !Object.keys(json).length) return ‘‘;
非空session,包含之前的用户数据
用户数据的有效性(期)即session的有效性(期)
koa-session 的 ContextSession类的实例-----contextSession对象,用来操作 session 和 externalKey(即sessionId)
koa 中引用的第三方库 cookies 中对 maxAge 和 expires 字段的处理逻辑
if (this.maxAge) this.expires = new Date(Date.now() + this.maxAge);
session有效期 和 cookie有效期由配置项maxAge
的值决定。
session中通过_maxAge 和 _expire
字段判断。cookie 中通过 maxAge
字段判断
maxAge=‘session‘
,表示有效期为 session,关闭浏览器后过期
_expire 和 _maxAge
字段,只添加 _session
maxAge
字段为 undefinedmaxAge = number
,表示有效期为 number时间,number时间后过期
_expire 和 _maxAge
字段,且_maxAge = maxAge
maxAge
字段为 number每次保存session,都会重置有效期
如果之前的session有效,则初始化session的时候会覆盖传入的配置项maxAge
,使用上次的值
if (k === ‘_maxAge‘) this._ctx.sessionOptions.maxAge = obj._maxAge; else if (k === ‘_session‘) this._ctx.sessionOptions.maxAge = ‘session‘;
如果采用外部存储,外部存储需要清理过期session,此时根据的是 maxAge += 10000
的值
保证外部存储在cookie过期之后清除用户数据
if (typeof maxAge === ‘number‘) {
// ensure store expired after cookie
maxAge += 10000;
}
session——会话对象,用于 存储 用户数据(value),不包括 sessionId
如果 session 存储在cookie中(默认)
没有 externalKey 即 sessionId
session 直接从 cookie 中获取
修改 session 就创建一个新的 cookie 保存
如果 session 存储在外部存储中,以键值对的形式存储 sessionId--session
有 externalKey 即 sessionId
需要根据 externalKey 从外部存储中 获取和更新 session
session 有效期内,修改 session
不创建新的 externalKey(键),仅修改 externalKey 对应的 value(值)
如果 externalKey 由外面提供,则由外面保存
如果 externalKey 由 koa-session 内部生成,则创建一个新的 cookie 保存
cookie 中仅存储 externalKey
除了用户数据,koa-session 中的 session 对象会添加额外的字段,用于 session 过期检测
json._expire = maxAge + Date.now(); json._maxAge = maxAge; // 有效期为session,会话cookie,关闭浏览器后消失 json._session = true
匿名函数(或理解为 session 函数)
const session = require(‘koa-session‘)
app.use(session(sessionConfig, app))
供外面调用,接收两个参数 opts 和 app
app
opts 配置对象
共用于 cookie 和 session 的配置
只用于 cookie 的配置
只用于 session 的配置
rolling
renew
autoCommit
prefix
自定义 externalKey 的前缀
只有当使用默认生成方法时才有效,即提供 genid 配置则无效
genid
自定义 生成 externalKey 的方法,默认 uuid.v4()
方法
一个函数,接收参数 ctx,genid(ctx)
externalKey
自定义 externalKey 的 获取 和 存储,生成方式对 koa-session 透明
一个对象,提供两个方法
get(ctx)
: get the external key
set(ctx, value)
: set the external key
store
自定义 session的外部存储
一个对象,提供三个方法
get(key, maxAge, { rolling })
: get session object by keyset(key, sess, maxAge, { rolling, changed })
: set session object for key, with a maxAge
(in ms)destroy(key)
: destroy session for keyContextStore
If your session store requires data or utilities from context, opts.ContextStore
is also supported. ContextStore
must be a class which claims three instance methods demonstrated above. new ContextStore(ctx)
will be executed on every reques
一个对象,提供三个方法(同 store 配置项)
valid
自定义 验证session有效性的额外方法
一个函数,接收两个参数,(ctx, value)
逻辑
参数校验和参数位置兼容
// 兼容性处理,参数位置 // session(app[, opts]) if (opts && typeof opts.use === ‘function‘) { [ app, opts ] = [ opts, app ]; } // app required if (!app || typeof app.use !== ‘function‘) { throw new TypeError(‘app instance required: `session(opts, app)`‘); }
formatOpts(opts)
格式化传入的配置(校验配置项、赋默认值)
extendContext(app.context, opts)
在 koa 中 ctx 对象的原型 app.context
上通过Object.defineProperties()
扩展属性
[CONTEXT_SESSION]
【私有】属性
用 Symbol 值作为属性名(外面无法访问),避免覆盖原有属性
const CONTEXT_SESSION = Symbol(‘context#contextSession‘)
[_CONTEXT_SESSION]
去访问的,其属性值是创建的 contextSession 实例,访问[CONTEXT_SESSION]
的时候去判断 [_CONTEXT_SESSION]
是否存在,存在就直接返回实例,不存在就创建一个新的实例。保证单次访问只有一个 contextSession 实例session
【公共】属性
get()
方法获取set()
方法设置sessionOptions
【公共】属性
- 因为 opts 是传给了 ContextSession 构造函数,必须通过 contextSession 对象去访问
- 但是因为
[CONTEXT_SESSION]
是私有属性,外面无法访问,只能内部访问。所以提供一个公共属性 sessionOptions 供外面访问配置对象opts
返回一个异步函数 session (中间件)
async function session(ctx, next){...}
next
方法后面的逻辑sess.store = true
,则立即调用initFromExternal()
方法创建一个新的 session 对象next()
过程中抛出异常,则将异常向外抛出finally
,默认情况下autoCommit = true
,调用 commit
方法,对当前 session对象 做最后的处理传入两个参数constructor(ctx, opts){...}
ctx
app.context 原型对象
opts
用户传入的配置对象
this.ctx
构造函数中赋值
值为 app.context 原型对象
this.app
构造函数中赋值
值为 koa 实例
用于触发 koa实例 app 上监听的事件
this.opts
构造函数中赋值
值为 用户传入的配置对象
浅克隆一份
Object.assign({}, opts)
this.store
this.session
在 set
和 create
方法中被赋值
set
中 this.session = false
,走删除逻辑
create
中this.session = new Session()
,创建新的session实例
值可能为
false
外面赋值ctx.session = null
,删除该 session
undefined
外面未访问ctx.session
且 非外部存储opt.store=undefined
,此时值为 undefined
session实例
外面访问 ctx.session
或 采用外部存储
this.externalKey
create
方法中被赋值initFromExternal
方法中获取)this.prevHash
在 initFromXxx
中被赋值
值为
表示 用户数据的hash值
采用
session.toJSON()
之后的数据,去除 koa-session 添加的属性,仅计算用户数据
用来判断本次处理请求的过程中 用户数据 是否被修改(添加、删除、更新)
get()
外面访问ctx.session
的时候被调用,用来获取 session
如果session已经存在,则返回 session实例
单次请求只有一个session实例
如果session被用户删除,则返回 null
如果 session不存在,根据store
配置选择创建方式
如果是外部存储,则调用create()
创建一个空的session
如果是cookie存储,则调用initFromCookie()
基于cookie创建session
惰性单例模式
set()
外面赋值 ctx.session =
的时候被调用,用于给 session 重新赋值
如果外部赋值为null,则内部赋值为 false(删除该 session)
如果外部赋值为一个 object,则创建一个新的session实例返回
如果存在 externalKey ,则不创建新的
use the original
externalKey
if exists to avoid waste storage
其他值则报错
async initFromExternal()
initFromCookie()
get
方法中被调用,用于从 【cookie存储】 初始化 session 对象valid(value, key)
在 initFromXxx
被调用
验证session的有效性,同时触发事件,外部可以做相应的动作
如果 session 不存在,返回 false--无效,触发 ‘missed‘ 事件
如果 session 过期,返回 false--无效,触发 ‘expired‘ 事件
如果 不满足自定义验证,返回 false--无效,触发 ‘invalid‘ 事件
其他返回 true--有效
emit(event, data)
只有在 valid(value, key)
方法中被调用
用于【异步触发】koa实例app上监听的事件
宏任务 setImmediate
setImmediate(() => { this.app.emit(`session:${event}`, data); });
create(val, externalKey)
在get()
、set()
、 async initFromExternal()
和 initFromCookie()
方法中被调用
逻辑
创建新的session
如果是外部存储,没有externalKey 或 session 无效,则创建新的 externalKey
async commit()
在暴露给外面的session方法中被调用,用于session的最后处理
逻辑
如果处理请求的过程中没有访问 session,则不处理
如果处理请求的过程中有访问session
如果赋值 session=null
,则删除session
其他情况视 _shouldSaveSession() 的返回结果决定是否保存
如果提供了钩子,则在保存之前执行
_shouldSaveSession()
只有在 async commit()
中被调用,用于判断是否保存当前session对象
操作
如果_requireSave = true
,则保存,返回 ‘force‘
用户调用
ctx.session.save()
强制保存,或调用ctx.session.maxAge(val)
更新 maxAge
如果当前session是新的(空session)且处理请求的过程中没有添加用户数据,则不保存,返回 ‘‘
// do nothing if new and not populated const json = session.toJSON(); // 如果 preHash 为undefined,则当前session为空(新) // 如果 length 为 0 ,则当前session在处理请求的过程中没有添加用户数据 if (!prevHash && !Object.keys(json).length) return ‘‘;
如果 当前session中的用户数据 和 上次保存的用户数据 的hash值不同,则保存,返回 ‘changed‘
// save if session changed const changed = prevHash !== util.hash(json); if (changed) return ‘changed‘;
如果配置项rolling=true
,则保存,返回 ‘rolling‘
如果配置项renew=true
且session即将过期expire - Date.now() < maxAge / 2
,则保存,返回 ‘renew‘
// save if opts.renew and session will expired if (this.opts.renew) { const expire = session._expire; // 注意:这里使用的是配置中的maxAge,而非session中的_maxAge // 1. session初始化的时候已经同步了上次的_maxAge // 2. 处理请求的过程中,用户有可以会修改maxAge的值 const maxAge = session.maxAge; // renew when session will expired in maxAge / 2 if (expire && maxAge && expire - Date.now() < maxAge / 2) return ‘renew‘; }
其他情况不保存,返回 ‘‘
async remove()
只有在 async commit()
中被调用,用来删除 session
覆盖配置项 expires、maxAge的值,让客户端的 cookie 立即过期
expires: COOKIE_EXP_DATE, // ‘Thu, 01 Jan 1970 00:00:00 GMT‘ maxAge: false, // 条件不成立,不会重新赋值expires
koa 使用的第三方库 cookies 对 maxAge 和 expires 的处理逻辑如下
if (this.maxAge) this.expires = new Date(Date.now() + this.maxAge);
调用外部存储提供的 destory
方法,删除 externalKey 对应的 session
async save(changed)
只有在 async commit()
中被调用,用于保存session
逻辑
获取 session 中的用户数据
let json = this.session.toJSON();
处理用户数据,添加字段用于判断有效期。根据配置项 maxAge 的值
如果值是 ‘session‘,则有效期为整个会话期间,关闭浏览器过期
_expired
字段,将过期判断交给浏览器,如果请求中携带了cookie,则证明仍处于会话期间,有效。否则无效_session
字段,用于下次请求初始化session时,覆盖默认配置// do not set _expire in json if maxAge is set to ‘session‘ // also delete maxAge from options opts.maxAge = undefined; json._session = true;
如果值是 number,则有效期为 number 时间
_expire 和 _maxAge
字段用来校验session的有效性保存用户数据
store.set
方法,将用户数据存储到外部存储externalKey.set
方法,保存当前用户数据对应的 externalKey接收两个参数constructor(sessionContext, obj)
sessionContext
contextSession 实例
obj
上次保存的 用户数据
如果 obj 为 undefined,则添加isNew
属性,值为 true
如果 obj 不为 undefined,则遍历obj,初始化 session 对象
重置用户传入配置项 maxAge 的值
因为如果上次用户调用
ctx.session.maxAge=
单独修改 maxAge 的值(非配置中的值),则本次保存要使用之前的值if (k === ‘_maxAge‘) this._ctx.sessionOptions.maxAge = obj._maxAge; else if (k === ‘_session‘) this._ctx.sessionOptions.maxAge = ‘session‘;
不明白这里为什么通过
_ctx.sessionOptions
访问 maxAge。可以直接通过_sessCtx.opts
访问?// 测试 结果为 true debug(‘--------是否相同------- ?‘,this._ctx.sessionOptions === this._sessCtx.opts)
this._sessCtx
this._ctx
构造函数中赋值
值为 app.context原型
this.isNew
构造函数中赋值
如果是空session,则值为true。
在 toJSON
方法中被丢弃
可用于判断是否登录
if (this.session.isNew) {
// user has not logged in
} else {
// user has already logged in
}
this.maxAge
_requireSave = true
this.length
this.populated
length属性的布尔值,仅用于判断 session 是否为空(没有添加用户数据)
true:当前session非空,有用户数据
false:当前session为空,没有用户数据
!!this.length
this._requireSave
toJSON()
将session对象转为json格式,仅保留用户数据
过滤掉isNew 、_expire、 _maxAge 、_requireSave、_session
等koa-session添加的内部属性(非用户数据)
if (key === ‘isNew‘) return;
if (key[0] === ‘_‘) return;
inspect()
save()
令 _requireSave = true
强制保存当前session,无论是否有修改
save this session no matter whether it is populated
async manuallyCommit()
工具类,提供session的编码和解码方式以及计算hash值的方法
标签:return 验证 签名 signed 发送 final 其他 alt 匿名函数
原文地址:https://www.cnblogs.com/usmile/p/13386650.html