mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 23:53:15 +08:00
change log in
This commit is contained in:
parent
9cf026f605
commit
8ca42dd973
211 changed files with 48417 additions and 109 deletions
27
uds-auth/lib/session/factory.js
Normal file
27
uds-auth/lib/session/factory.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { MemoryStore } from './memory-store.js'
|
||||
import { RedisStore } from './redis-store.js'
|
||||
|
||||
/**
|
||||
* Factory function to create appropriate session store based on config
|
||||
* @param {object} config - Session configuration
|
||||
* @returns {Promise<SessionStore>}
|
||||
*/
|
||||
export async function createSessionStore(config) {
|
||||
const { storeType, redisUrl } = config
|
||||
|
||||
if (storeType === 'redis') {
|
||||
try {
|
||||
const { createClient } = await import('redis')
|
||||
const client = createClient({ url: redisUrl })
|
||||
await client.connect()
|
||||
return new RedisStore(client)
|
||||
} catch (err) {
|
||||
console.error('[uds-auth] Failed to connect to Redis:', err.message)
|
||||
console.warn('[uds-auth] Falling back to MemoryStore')
|
||||
return new MemoryStore()
|
||||
}
|
||||
}
|
||||
|
||||
// Default to memory store
|
||||
return new MemoryStore()
|
||||
}
|
||||
61
uds-auth/lib/session/memory-store.js
Normal file
61
uds-auth/lib/session/memory-store.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { SessionStore } from './store.js'
|
||||
|
||||
/**
|
||||
* In-memory session store — 单索引 empNo → userData
|
||||
* 一个工号 = 一个会话,多终端同工号共享同一条目。
|
||||
*/
|
||||
export class MemoryStore extends SessionStore {
|
||||
constructor() {
|
||||
super()
|
||||
this._sessions = new Map() // Map<empNo, { userData, expiresAt }>
|
||||
this._timers = new Map() // Map<empNo, Timeout>
|
||||
}
|
||||
|
||||
async get(empNo) {
|
||||
const session = this._sessions.get(empNo)
|
||||
if (!session) return null
|
||||
if (session.expiresAt && Date.now() > session.expiresAt) {
|
||||
await this.delete(empNo)
|
||||
return null
|
||||
}
|
||||
return { ...session.userData }
|
||||
}
|
||||
|
||||
async set(empNo, userData) {
|
||||
this._sessions.set(empNo, { userData })
|
||||
}
|
||||
|
||||
async setex(empNo, seconds, userData) {
|
||||
this._sessions.set(empNo, { userData, expiresAt: Date.now() + seconds * 1000 })
|
||||
if (this._timers.has(empNo)) clearTimeout(this._timers.get(empNo))
|
||||
this._timers.set(empNo, setTimeout(() => this._sessions.delete(empNo), seconds * 1000))
|
||||
}
|
||||
|
||||
async delete(empNo) {
|
||||
if (this._timers.has(empNo)) {
|
||||
clearTimeout(this._timers.get(empNo))
|
||||
this._timers.delete(empNo)
|
||||
}
|
||||
this._sessions.delete(empNo)
|
||||
}
|
||||
|
||||
async has(empNo) {
|
||||
const session = this._sessions.get(empNo)
|
||||
if (!session) return false
|
||||
if (session.expiresAt && Date.now() > session.expiresAt) {
|
||||
await this.delete(empNo)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async clear() {
|
||||
for (const t of this._timers.values()) clearTimeout(t)
|
||||
this._timers.clear()
|
||||
this._sessions.clear()
|
||||
}
|
||||
|
||||
async keys() {
|
||||
return Array.from(this._sessions.keys())
|
||||
}
|
||||
}
|
||||
47
uds-auth/lib/session/redis-store.js
Normal file
47
uds-auth/lib/session/redis-store.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { SessionStore } from './store.js'
|
||||
|
||||
/**
|
||||
* Redis-backed session store (for production / 多实例)
|
||||
* Requires 'redis' package: npm install redis
|
||||
* Key: uds-session:{empNo}
|
||||
*/
|
||||
export class RedisStore extends SessionStore {
|
||||
constructor(redisClient) {
|
||||
super()
|
||||
if (!redisClient) throw new Error('Redis client is required')
|
||||
this._client = redisClient
|
||||
}
|
||||
|
||||
_key(empNo) { return `uds-session:${empNo}` }
|
||||
|
||||
async get(empNo) {
|
||||
const data = await this._client.get(this._key(empNo))
|
||||
return data ? JSON.parse(data) : null
|
||||
}
|
||||
|
||||
async set(empNo, userData) {
|
||||
await this._client.set(this._key(empNo), JSON.stringify(userData))
|
||||
}
|
||||
|
||||
async setex(empNo, seconds, userData) {
|
||||
await this._client.setEx(this._key(empNo), seconds, JSON.stringify(userData))
|
||||
}
|
||||
|
||||
async delete(empNo) {
|
||||
await this._client.del(this._key(empNo))
|
||||
}
|
||||
|
||||
async has(empNo) {
|
||||
return (await this._client.exists(this._key(empNo))) === 1
|
||||
}
|
||||
|
||||
async clear() {
|
||||
const keys = await this._client.keys('uds-session:*')
|
||||
if (keys.length > 0) await this._client.del(keys)
|
||||
}
|
||||
|
||||
async keys() {
|
||||
const all = await this._client.keys('uds-session:*')
|
||||
return all.map(k => k.replace(/^uds-session:/, ''))
|
||||
}
|
||||
}
|
||||
22
uds-auth/lib/session/store.js
Normal file
22
uds-auth/lib/session/store.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Session store — 单索引: empNo → userData
|
||||
*
|
||||
* 一个工号 = 一个会话,不需要 sessionId,不需要额外 cookie。
|
||||
* 多终端同工号自动共享同一个会话条目。
|
||||
*/
|
||||
export class SessionStore {
|
||||
/** 按 empNo 获取会话 */
|
||||
async get(empNo) { throw new Error('SessionStore#get must be implemented') }
|
||||
/** 按 empNo 存储会话 */
|
||||
async set(empNo, userData) { throw new Error('SessionStore#set must be implemented') }
|
||||
/** 按 empNo 存储并设置过期(秒) */
|
||||
async setex(empNo, seconds, userData) { throw new Error('SessionStore#setex must be implemented') }
|
||||
/** 按 empNo 删除会话 */
|
||||
async delete(empNo) { throw new Error('SessionStore#delete must be implemented') }
|
||||
/** 检查 empNo 是否存在 */
|
||||
async has(empNo) { throw new Error('SessionStore#has must be implemented') }
|
||||
/** 清空所有会话 */
|
||||
async clear() { throw new Error('SessionStore#clear must be implemented') }
|
||||
/** 列出所有活跃会话 */
|
||||
async keys() { throw new Error('SessionStore#keys must be implemented') }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue