mirror of
https://github.com/chaos-zhu/easynode.git
synced 2026-10-07 15:08:33 +08:00
feat: 优化 session 管理
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
import { KeyDB, SessionDB } from '../utils/db-class.js'
|
||||
import { cookieSecure } from '../config/index.js'
|
||||
import { disconnectAllSessionConnections, revokeAllSessions } from '../utils/auth-session.js'
|
||||
import { pruneLoginLogs } from '../utils/login-log.js'
|
||||
const keyDB = new KeyDB().getInstance()
|
||||
const sessionDB = new SessionDB().getInstance()
|
||||
|
||||
async function getLog({ res }) {
|
||||
await pruneLoginLogs(sessionDB)
|
||||
let sessionList = await sessionDB.findAsync({})
|
||||
let { ipWhiteList = [] } = await keyDB.findOneAsync({}) || {}
|
||||
ipWhiteList = ipWhiteList.filter(ip => typeof ip === 'string' && ip.trim() !== '')
|
||||
@@ -24,13 +28,6 @@ const saveIpWhiteList = async ({ res, request }) => {
|
||||
res.success({ msg: 'success' })
|
||||
}
|
||||
|
||||
const removeSomeLoginRecords = async ({ res }) => {
|
||||
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000
|
||||
const result = await sessionDB.removeAsync({ create: { $lt: sevenDaysAgo } }, { multi: true })
|
||||
if (result === 0) return res.success({ msg: '没有符合条件的登录日志' })
|
||||
res.success({ msg: `已成功移除 ${ result } 条登录日志` })
|
||||
}
|
||||
|
||||
const revokeLoginSid = async (ctx) => {
|
||||
const { res, request, cookies } = ctx
|
||||
let { params: { id } } = request
|
||||
@@ -50,9 +47,25 @@ const revokeLoginSid = async (ctx) => {
|
||||
res.success({ msg: '注销凭证成功' })
|
||||
}
|
||||
|
||||
const revokeAllLoginSessions = async (ctx) => {
|
||||
try {
|
||||
await revokeAllSessions(sessionDB)
|
||||
} finally {
|
||||
// 已建立的长连接不会再次经过鉴权,需要主动断开。
|
||||
disconnectAllSessionConnections()
|
||||
}
|
||||
ctx.cookies.set('session', '', {
|
||||
httpOnly: true,
|
||||
expires: new Date(0),
|
||||
sameSite: 'strict',
|
||||
secure: cookieSecure
|
||||
})
|
||||
ctx.res.success({ msg: '已注销所有会话,请重新登录' })
|
||||
}
|
||||
|
||||
export {
|
||||
getLog,
|
||||
saveIpWhiteList,
|
||||
removeSomeLoginRecords,
|
||||
revokeAllLoginSessions,
|
||||
revokeLoginSid
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getGroupList, addGroupList, updateGroupList, removeGroup } from '../con
|
||||
import { getScriptList, getLocalScriptList, addScript, updateScriptList, removeScript, batchRemoveScript, importScript } from '../controller/scripts.js'
|
||||
import { getScriptGroupList, addScriptGroup, removeScriptGroup, updateScriptGroup } from '../controller/script-group.js'
|
||||
import { getOnekeyRecord, removeOnekeyRecord } from '../controller/onekey.js'
|
||||
import { getLog, saveIpWhiteList, removeSomeLoginRecords, revokeLoginSid } from '../controller/sessionLog.js'
|
||||
import { getLog, saveIpWhiteList, revokeAllLoginSessions, revokeLoginSid } from '../controller/sessionLog.js'
|
||||
import { getAIConfig, saveAIConfig, getAIModels, updateAIPreferences } from '../controller/chat.js'
|
||||
import { getAgentSessions, getAgentSessionDetail, updateAgentSession, forkAgentSession, removeAgentSession, clearAgentSessions, editAgentSessionMessage } from '../controller/agent-session.js'
|
||||
import { getAgentMcpServers, addAgentMcpServer, editAgentMcpServer, removeAgentMcpServer, testAgentMcpConnection, discoverAgentMcpServer } from '../controller/agent-mcp.js'
|
||||
@@ -294,11 +294,11 @@ const log = [
|
||||
path: '/ip-white-list',
|
||||
controller: saveIpWhiteList
|
||||
},
|
||||
{
|
||||
method: 'delete',
|
||||
path: '/remove-some-login-records',
|
||||
controller: removeSomeLoginRecords
|
||||
},
|
||||
{
|
||||
method: 'delete',
|
||||
path: '/revoke-all-sessions',
|
||||
controller: revokeAllLoginSessions
|
||||
},
|
||||
{
|
||||
method: 'delete',
|
||||
path: '/revoke-login/:id',
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import schedule from 'node-schedule'
|
||||
import { sendNoticeAsync } from '../utils/notify.js'
|
||||
import { formatTimestamp } from '../utils/tools.js'
|
||||
import { HostListDB } from '../utils/db-class.js'
|
||||
import { HostListDB, SessionDB } from '../utils/db-class.js'
|
||||
import { LOGIN_LOG_RETENTION_DAYS, pruneLoginLogs } from '../utils/login-log.js'
|
||||
const hostListDB = new HostListDB().getInstance()
|
||||
const sessionDB = new SessionDB().getInstance()
|
||||
|
||||
const expiredNotifyJob = async () => {
|
||||
const expiredNotifyJob = async () => {
|
||||
logger.info('=====开始检测服务器到期时间=====', new Date())
|
||||
const hostList = await hostListDB.findAsync({})
|
||||
for (const item of hostList) {
|
||||
@@ -25,8 +27,14 @@ const expiredNotifyJob = async () => {
|
||||
sendNoticeAsync('host_expired', title, temp + content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const loginLogRetentionJob = async () => {
|
||||
const removed = await pruneLoginLogs(sessionDB)
|
||||
if (removed > 0) logger.info(`已清理 ${ removed } 条超过 ${ LOGIN_LOG_RETENTION_DAYS } 天的登录日志`)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
schedule.scheduleJob('0 0 12 1/1 * ?', expiredNotifyJob)
|
||||
schedule.scheduleJob('0 0 3 * * *', loginLogRetentionJob)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
const LOGIN_LOG_RETENTION_DAYS = 90
|
||||
const DAY_MS = 24 * 60 * 60 * 1000
|
||||
|
||||
const pruneLoginLogs = (sessionStore, now = Date.now()) => {
|
||||
const cutoff = now - LOGIN_LOG_RETENTION_DAYS * DAY_MS
|
||||
return sessionStore.removeAsync(
|
||||
{ create: { $lt: cutoff } },
|
||||
{ multi: true }
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
LOGIN_LOG_RETENTION_DAYS,
|
||||
pruneLoginLogs
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
registerSocketServer,
|
||||
revokeAllSessions
|
||||
} from '../app/utils/auth-session.js'
|
||||
import { LOGIN_LOG_RETENTION_DAYS, pruneLoginLogs } from '../app/utils/login-log.js'
|
||||
|
||||
const calls = []
|
||||
const sessionStore = {
|
||||
@@ -35,6 +36,19 @@ const storedSessions = await realSessionStore.findAsync({})
|
||||
assert.equal(storedSessions.length, 3)
|
||||
assert.ok(storedSessions.every(session => session.revoked === true))
|
||||
|
||||
const now = Date.UTC(2026, 7, 29)
|
||||
const loginLogStore = new Datastore()
|
||||
await loginLogStore.insertAsync([
|
||||
{ session: 'old', create: now - (LOGIN_LOG_RETENTION_DAYS + 1) * 24 * 60 * 60 * 1000 },
|
||||
{ session: 'boundary', create: now - LOGIN_LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000 },
|
||||
{ session: 'recent', create: now - 10 * 24 * 60 * 60 * 1000 }
|
||||
])
|
||||
assert.equal(await pruneLoginLogs(loginLogStore, now), 1)
|
||||
assert.deepEqual(
|
||||
(await loginLogStore.findAsync({})).map(item => item.session).sort(),
|
||||
['boundary', 'recent']
|
||||
)
|
||||
|
||||
let disconnectCalls = 0
|
||||
let destroyCalls = 0
|
||||
const closeListeners = []
|
||||
|
||||
Reference in New Issue
Block a user