关闭未认证的WebSocket连接并重构Redis服务

在WebSocket认证失败时,主动关闭连接以提高安全性。重构了Redis服务中的方法,使其更加通用,并更新了相关的导入和调用。同时,调整了数据持久化路径的生成方式,支持自定义文件名。
This commit is contained in:
Jerry 2025-04-17 13:36:41 +08:00
parent a996bed065
commit 4a82585c29
3 changed files with 36 additions and 57 deletions

View File

@ -2,9 +2,9 @@ import Redis from 'ioredis';
import logger from '../../utils/core/logger';
import tools from '../../utils/core/tool';
import config from '../../utils/core/config';
import redisTool from '../../utils/redis/redisTools';
import IUser from '../../types/user';
import redisTools from '../../utils/redis/redisTools';
import Persistence from '../../utils/redis/persistence';
import IUser from '../../types/user';
class RedisService {
private client!: Redis;
@ -93,7 +93,7 @@ class RedisService {
}
public async setObject<T>(key: string, value: T, ttl?: number): Promise<void> {
const serialized = redisTool.serialize(value);
const serialized = redisTools.serialize(value);
await this.getClient().set(key, serialized);
if (ttl) {
@ -105,66 +105,40 @@ class RedisService {
const serialized = await this.getClient().get(key);
if (!serialized) return undefined;
const deserialized = redisTool.deserialize<T>(serialized);
return redisTool.reviveDates(deserialized);
const deseralized = redisTools.deserialize<T>(serialized);
return redisTools.reviveDates(deseralized);
}
public async updateUser(qq: string, updates: Partial<IUser>): Promise<IUser> {
const existing = await this.getObject<IUser>(`user:${qq}`);
public async update<T>(key: string, updates: T): Promise<T> {
const existing = await this.getObject<T>(key);
if (!existing) {
throw new Error(`用户 ${qq} 不存在`);
logger.error(`数据${key}不存在..`);
}
const updatedUser = { ...existing, ...updates, updatedAt: new Date() };
await this.persistUser(updatedUser);
return updatedUser;
const updated = { ...existing, ...updates };
await this.setObject(key, updated);
return updated;
}
public async persistUser<T extends IUser>(user: T): Promise<void> {
try {
await Promise.all([
this.setObject(`user:${user.qq}`, user),
Persistence.writeDataLocal(user.name, user),
]);
} catch (err) {
logger.error(err);
throw err;
public async fetch<T>(key: string, fileName: string): Promise<T | undefined> {
const data = await this.getObject<T>(key);
if (data) return data;
const fromLocal = await Persistence.readDataLocal<T>(key, fileName);
if (fromLocal) {
await this.setObject(key, fromLocal);
return fromLocal;
}
logger.error(`数据${key}不存在..`);
}
public async fetchUser<T extends IUser>(
qq: string,
username: string
): Promise<IUser | undefined> {
try {
const fromRedis = await this.getObject<IUser>(`user:${qq}`);
if (fromRedis) return fromRedis;
const fromLocal = await Persistence.readDataLocal<IUser>(username);
if (fromLocal) {
await this.setObject(`user:${qq}`, fromLocal);
return fromLocal;
}
logger.error(`用户${username},qq${qq}不存在!`);
return undefined;
} catch (err) {
logger.error(err);
throw err;
}
public async persistData<T>(key: string, data: T, fileName: string): Promise<void> {
await this.setObject(key, data);
await Persistence.writeDataLocal(key, data, fileName);
return;
}
public async test(): Promise<void> {
const testData: IUser = {
name: 'Jerry',
qq: '114514',
isAdmin: true,
password: '114514',
createdAt: new Date(),
};
await this.persistUser(testData);
const user = await this.fetchUser('114514', 'Jerry');
logger.debug(user);
const user = await this.fetch<IUser>('Jerry', 'IUser');
logger.debug('User:', user);
}
}

View File

@ -83,6 +83,7 @@ class WSServer {
} else {
logger.warn(`Auth failed from ${ip} (invalid secret), clientId: ${msg.clientId}`);
await WsTools.send(socket, { type: 'auth', success: false });
socket.close(4001, 'Authentication failed');
}
}

View File

@ -5,8 +5,8 @@ import logger from '../core/logger';
import fs from 'fs/promises';
class Persistence {
private static getUserDataPath(username: string): string {
return path.join(paths.get('userData'), username, 'data.json');
private static getUserDataPath(username: string, fileName: string): string {
return path.join(paths.get('userData'), username, `${fileName}.json`);
}
private static async ensureUserPath(username: string): Promise<void> {
@ -18,9 +18,13 @@ class Persistence {
}
}
public static async writeDataLocal<T>(username: string, data: T): Promise<void> {
public static async writeDataLocal<T>(
username: string,
data: T,
fileName: string
): Promise<void> {
await this.ensureUserPath(username);
const filePath = this.getUserDataPath(username);
const filePath = this.getUserDataPath(username, fileName);
try {
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
@ -30,8 +34,8 @@ class Persistence {
}
}
public static async readDataLocal<T>(username: string): Promise<T | undefined> {
const filePath = this.getUserDataPath(username);
public static async readDataLocal<T>(username: string, fileName: string): Promise<T | undefined> {
const filePath = this.getUserDataPath(username, fileName);
try {
const data = await fs.readFile(filePath, 'utf-8');