From f955869052c2e4c8bca7010cbb28c16d7227aa27 Mon Sep 17 00:00:00 2001 From: mzl92 Date: Fri, 28 Aug 2026 13:59:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E6=8C=81=E4=B9=85=E5=8C=96?= =?UTF-8?q?=E5=88=B0DB+=E6=9C=89=E6=95=88=E6=9C=9F=E5=BB=B6=E8=87=B37?= =?UTF-8?q?=E5=A4=A9:=20=E9=83=A8=E7=BD=B2=E9=87=8D=E5=90=AF=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E5=85=A8=E5=91=98=E7=99=BB=E5=87=BA(=E4=B9=8B?= =?UTF-8?q?=E5=89=8D=E4=BC=9A=E8=AF=9D=E5=9C=A8=E5=86=85=E5=AD=98,?= =?UTF-8?q?=E6=AF=8F=E6=AC=A1=E5=8F=91=E5=B8=83=E9=83=BD=E6=8A=8A=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=B8=A2=E4=B8=8B=E7=BA=BF)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 747b030..a238a54 100644 --- a/server.js +++ b/server.js @@ -94,12 +94,15 @@ let rdb = new Database(SNAP_PATH, { readonly: true }); // 注意: makeSnapshot 用 rename 覆盖快照文件后, 已打开的连接仍指向旧 inode(读到陈旧数据), // 必须在每次快照后重开连接(rdb 为 let 就是为此)。 -// ---------- 会话(内存态,重启需重登) ---------- -const sessions = new Map(); // sid -> { uid, role, expires } -const SESSION_HOURS = 12; +// ---------- 会话(持久化到users.db, 部署重启不再全员登出) ---------- +const sessions = new Map(); // sid -> { uid, role, expires } (内存缓存,源在DB) +const SESSION_HOURS = 168; // 7天 +udb.exec(`CREATE TABLE IF NOT EXISTS sessions (sid TEXT PRIMARY KEY, uid INTEGER NOT NULL, expires INTEGER NOT NULL)`); function newSession(uid, role) { const sid = crypto.randomBytes(24).toString('hex'); - sessions.set(sid, { uid, role, expires: Date.now() + SESSION_HOURS * 3600e3 }); + const expires = Date.now() + SESSION_HOURS * 3600e3; + sessions.set(sid, { uid, role, expires }); + try { udb.prepare('INSERT OR REPLACE INTO sessions (sid, uid, expires) VALUES (?,?,?)').run(sid, uid, expires); } catch (_) {} return sid; } function signSid(sid) { return sid + '.' + crypto.createHmac('sha256', SECRET).update(sid).digest('hex').slice(0, 16); } @@ -113,8 +116,18 @@ function parseSid(cookie) { function authUser(req) { const sid = parseSid(req.headers.cookie); if (!sid) return null; - const s = sessions.get(sid); - if (!s || s.expires < Date.now()) { sessions.delete(sid); return null; } + let s = sessions.get(sid); + if (!s) { // 容器重启后从DB恢复 + const row = udb.prepare('SELECT uid, expires FROM sessions WHERE sid = ?').get(sid); + if (row) { + if (row.expires < Date.now()) { udb.prepare('DELETE FROM sessions WHERE sid = ?').run(sid); return null; } + const u = udb.prepare('SELECT id, role FROM users WHERE id = ? AND disabled = 0').get(row.uid); + if (!u) return null; + s = { uid: u.id, role: u.role, expires: row.expires }; + sessions.set(sid, s); + } + } + if (!s || s.expires < Date.now()) { sessions.delete(sid); try { udb.prepare('DELETE FROM sessions WHERE sid = ?').run(sid); } catch (_) {} return null; } return udb.prepare('SELECT id, username, role FROM users WHERE id = ? AND disabled = 0').get(s.uid) || null; } @@ -151,7 +164,10 @@ app.post('/api/logout', (req, res) => { const sid = parseSid(req.headers.cookie); const me = authUser(req); if (me) logAccess(req, me.username, 'logout'); - if (sid) sessions.delete(sid); + if (sid) { + sessions.delete(sid); + try { udb.prepare('DELETE FROM sessions WHERE sid = ?').run(sid); } catch (_) {} + } res.setHeader('Set-Cookie', 'session=; HttpOnly; Path=/; Max-Age=0'); res.json({ ok: true }); });