From c9c3fb2f2b552b236f402a5fb2dd88d2720bcc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=87=E5=A4=A9?= Date: Thu, 24 Sep 2020 19:56:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BC=9A=E8=AF=9D=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 79 +++++++++++++++++++++++++++ lib/{native-store.js => mem-store.js} | 47 ++++++---------- lib/redis-store.js | 44 ++++++--------- session.js | 66 ---------------------- 4 files changed, 113 insertions(+), 123 deletions(-) create mode 100644 index.js rename lib/{native-store.js => mem-store.js} (54%) delete mode 100644 session.js diff --git a/index.js b/index.js new file mode 100644 index 0000000..a75bd77 --- /dev/null +++ b/index.js @@ -0,0 +1,79 @@ +/** + * 会话模块 + * @author yutent + * @date 2020/09/24 11:18:23 + */ + +import { uuid, sha1 } from 'crypto.js' + +import RedisStore from './lib/redis-store.js' +import MemStore from './lib/mem-store.js' + +// 会话储存器 +export const sessionStore = { + name: 'session', + install() { + var session = this.get('session') + + // 这里只创建session的存储器, 而初始化操作在中间件中进行 + if (session.type === 'redis') { + return new RedisStore(session) + } else { + return new MemStore(session) + } + } +} + +// 会话中间件 +export function sessionWare(req, res, next) { + var opt = this.get('session') + var jwt = this.get('jwt') + var ssid + + // options请求不处理会话 + if (req.method === 'OPTIONS') { + return next() + } + + // jwt模式的校验不在这里处理 + if (jwt) { + var auth = req.header('authorization') + if (auth) { + ssid = auth.split('.').pop() + this.$$session.start(ssid) + } + } else { + var cache = req.cookie('NODESSID') + var deviceID = '' + + // 校验UA + if (opt.level & 2) { + deviceID += req.header('user-agent') + } + + // 校验IP + if (opt.level & 4) { + deviceID += req.ip() + } + + if (deviceID) { + deviceID = sha1(deviceID) + + // ssid 最后16位是指纹 + if (cache) { + if (cache.slice(-16) === deviceID.slice(-16)) { + ssid = cache + } else { + ssid = uuid('') + deviceID.slice(-16) + } + } + } else { + ssid = cache || sha1(uuid()) + } + + res.cookie('NODESSID', ssid) + this.$$session.start(ssid) + } + + next() +} diff --git a/lib/native-store.js b/lib/mem-store.js similarity index 54% rename from lib/native-store.js rename to lib/mem-store.js index b52f9a5..98b99bc 100644 --- a/lib/native-store.js +++ b/lib/mem-store.js @@ -14,39 +14,28 @@ function hideProperty(host, name, value) { } export default class Session { - constructor(store, opt, uuid) { - this.opt = opt - this.uuid = uuid - this.store = store + constructor(opt) { + this.store = Object.create(null) + this.ttl = opt.ttl } - createSsid(ssid) { - if (ssid) { - if (!this.opt.jwt && this.opt.level > 0 && ssid !== this.uuid) { - ssid = this.uuid - } - } else { - ssid = this.uuid - } + start(ssid, oldssid) { + var session = this.store[ssid] + this.ssid = ssid - if ( - !this.store.hasOwnProperty(ssid) || - this.store[ssid].__EXPIRES__ < Date.now() - ) { - this.store[ssid] = {} + // 内存版会话管理, 没有设计计划任务来清理过期数据 + // 需要在初始化时先判断, 过期的自动清除, 没过期的, 直接重新续期 + if (session) { + if (Date.now() > session.__expires__) { + this.clear() + } + } else { + session = this.store[ssid] = {} } - //设置session有效期 - hideProperty( - this.store[ssid], - '__EXPIRES__', - Date.now() + this.opt.ttl * 1000 - ) - } - start(ssid) { - this.createSsid(ssid) - return this.ssid + // 设置session有效期 + hideProperty(session, '__expires__', Date.now() + this.ttl * 1000) } // 获取session字段值 @@ -67,9 +56,7 @@ export default class Session { // 删除单个字段 unset(key) { - if (this.store[this.ssid].hasOwnProperty(key)) { - delete this.store[this.ssid][key] - } + delete this.store[this.ssid][key] } // 清除个人session diff --git a/lib/redis-store.js b/lib/redis-store.js index 8896c85..e618ab3 100644 --- a/lib/redis-store.js +++ b/lib/redis-store.js @@ -4,30 +4,22 @@ * @date 2020/09/18 16:35:26 */ +import Ioredis from 'ioredis' + export default class Session { - constructor(store, opt, uuid) { - this.store = store - this.opt = opt - this.uuid = uuid - } - - createSsid(ssid) { - if (ssid) { - if (!this.opt.jwt && this.opt.level > 0 && ssid !== this.uuid) { - ssid = this.uuid - } - } else { - ssid = this.uuid - } - - this.ssid = ssid - // 设置session有效期 - this.store.expire(ssid, this.opt.ttl) + constructor(opt) { + this.store = new RedisStore({ + host: opt.db.host || '127.0.0.1', + port: opt.db.port || 6379, + db: opt.db.db || 0 + }) + this.ttl = opt.ttl } start(ssid) { - this.createSsid(ssid) - return this.ssid + this.ssid = ssid + // 设置session有效期 + this.store.expire(ssid, this.ttl) } // 获取session字段值, 需要await指令 @@ -40,17 +32,15 @@ export default class Session { } for (let i in obj) { - if (!obj[i]) { - continue + if (obj[i]) { + obj[i] = Number.parse(obj[i]) } - - obj[i] = Number.parse(obj[i]) } //不传key时,直接返回全部字段 - if (!key) { - defer.resolve(obj) - } else { + if (key) { defer.resolve(obj.hasOwnProperty(key) ? obj[key] : null) + } else { + defer.resolve(obj) } }) return defer.promise diff --git a/session.js b/session.js deleted file mode 100644 index 8ae5b8d..0000000 --- a/session.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-07-26 15:50:25 - * @version $Id$ - */ -import redisStore from './lib/redis-store.js' -import nativeStore from './lib/native-store.js' -import { uuid, sha1 } from 'crypto.js' - -export default function(req, res, next) { - var opt = this.get('session') - var jwt = this.get('jwt') - var cookie = this.ins('cookie') - var session = null - var deviceID = uuid() - var ssid = '' - - opt.jwt = jwt - - if (req.method === 'OPTIONS') { - return next() - } - - if (jwt) { - var auth = req.header('authorization') - if (auth) { - ssid = auth.split('.').pop() - deviceID = auth - } - } else { - ssid = cookie('NODESSID') - // 校验级别为1, 则混入ua - if (opt.level > 0) { - deviceID += req.header('user-agent') - } - // 校验级别为2, 则混入ip - if (opt.level > 1) { - deviceID += req.ip() - } - } - deviceID = sha1(deviceID) - - if (opt.type === 'redis') { - session = new redisStore(this.__SESSION_STORE__, opt, deviceID) - } else { - session = new nativeStore(this.__SESSION_STORE__, opt, deviceID) - } - - // 启用SESSION - // ssid非法或过期时,需要重写 - if (!ssid || ssid !== session.start(ssid)) { - ssid = session.start(ssid) - if (!jwt) { - cookie('NODESSID', ssid, { - httpOnly: true, - expires: opt.ttl, - domain: opt.domain - }) - } - } - - this.__INSTANCE__.session = session - - next() -}