完成会话管理

v1
宇天 2020-09-24 19:56:01 +08:00
parent a0b4c57db3
commit c9c3fb2f2b
4 changed files with 113 additions and 123 deletions

79
index.js Normal file
View File

@ -0,0 +1,79 @@
/**
* 会话模块
* @author yutent<yutent.io@gmail.com>
* @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()
}

View File

@ -14,39 +14,28 @@ function hideProperty(host, name, value) {
} }
export default class Session { export default class Session {
constructor(store, opt, uuid) { constructor(opt) {
this.opt = opt this.store = Object.create(null)
this.uuid = uuid this.ttl = opt.ttl
this.store = store
} }
createSsid(ssid) { start(ssid, oldssid) {
if (ssid) { var session = this.store[ssid]
if (!this.opt.jwt && this.opt.level > 0 && ssid !== this.uuid) {
ssid = this.uuid
}
} else {
ssid = this.uuid
}
this.ssid = ssid this.ssid = ssid
if ( // 内存版会话管理, 没有设计计划任务来清理过期数据
!this.store.hasOwnProperty(ssid) || // 需要在初始化时先判断, 过期的自动清除, 没过期的, 直接重新续期
this.store[ssid].__EXPIRES__ < Date.now() if (session) {
) { if (Date.now() > session.__expires__) {
this.store[ssid] = {} this.clear()
} }
//设置session有效期 } else {
hideProperty( session = this.store[ssid] = {}
this.store[ssid],
'__EXPIRES__',
Date.now() + this.opt.ttl * 1000
)
} }
start(ssid) { // 设置session有效期
this.createSsid(ssid) hideProperty(session, '__expires__', Date.now() + this.ttl * 1000)
return this.ssid
} }
// 获取session字段值 // 获取session字段值
@ -67,10 +56,8 @@ export default class Session {
// 删除单个字段 // 删除单个字段
unset(key) { unset(key) {
if (this.store[this.ssid].hasOwnProperty(key)) {
delete this.store[this.ssid][key] delete this.store[this.ssid][key]
} }
}
// 清除个人session // 清除个人session
clear() { clear() {

View File

@ -4,30 +4,22 @@
* @date 2020/09/18 16:35:26 * @date 2020/09/18 16:35:26
*/ */
import Ioredis from 'ioredis'
export default class Session { export default class Session {
constructor(store, opt, uuid) { constructor(opt) {
this.store = store this.store = new RedisStore({
this.opt = opt host: opt.db.host || '127.0.0.1',
this.uuid = uuid port: opt.db.port || 6379,
} db: opt.db.db || 0
})
createSsid(ssid) { this.ttl = opt.ttl
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)
} }
start(ssid) { start(ssid) {
this.createSsid(ssid) this.ssid = ssid
return this.ssid // 设置session有效期
this.store.expire(ssid, this.ttl)
} }
// 获取session字段值, 需要await指令 // 获取session字段值, 需要await指令
@ -40,17 +32,15 @@ export default class Session {
} }
for (let i in obj) { for (let i in obj) {
if (!obj[i]) { if (obj[i]) {
continue
}
obj[i] = Number.parse(obj[i]) obj[i] = Number.parse(obj[i])
} }
}
//不传key时,直接返回全部字段 //不传key时,直接返回全部字段
if (!key) { if (key) {
defer.resolve(obj)
} else {
defer.resolve(obj.hasOwnProperty(key) ? obj[key] : null) defer.resolve(obj.hasOwnProperty(key) ? obj[key] : null)
} else {
defer.resolve(obj)
} }
}) })
return defer.promise return defer.promise

View File

@ -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()
}