From 75e663f74e4380e3ac0b6a34bce9c272f65a387a Mon Sep 17 00:00:00 2001 From: pipipigua <396076883@qq.com> Date: Thu, 31 Oct 2024 21:19:37 +0800 Subject: [PATCH] =?UTF-8?q?log=E8=AE=B0=E5=BD=95=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/mysql/index.ts | 18 ++++++----- src/router/http.ts | 66 +++++++++++++++++++++++++-------------- src/server.ts | 1 + src/utils/auth.ts | 26 +++++++++++++++ src/utils/operationLog.ts | 28 ++++++++++------- 5 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 src/utils/auth.ts diff --git a/src/models/mysql/index.ts b/src/models/mysql/index.ts index 91eeed2..0b4dbf5 100644 --- a/src/models/mysql/index.ts +++ b/src/models/mysql/index.ts @@ -44,17 +44,19 @@ const userRole = ` /** 创建操作日志表 */ const operationLogs = ` - CREATE TABLE IF NOT EXISTS operation_logs ( +CREATE TABLE IF NOT EXISTS operation_logs ( id INT PRIMARY KEY AUTO_INCREMENT, - user_id INT NOT NULL, - username VARCHAR(255), - action VARCHAR(255) NOT NULL COMMENT '操作类型:新增、修改、删除等', - module VARCHAR(255) NOT NULL COMMENT '操作模块:用户管理、角色管理等', - description TEXT COMMENT '操作详细描述', + operator_id INT NOT NULL COMMENT '操作者ID', + operator_name VARCHAR(100) NOT NULL COMMENT '操作者名称', + target_id INT COMMENT '被操作对象ID', + target_type VARCHAR(50) COMMENT '被操作对象类型(如:user, role等)', + action VARCHAR(50) NOT NULL COMMENT '操作类型:CREATE, UPDATE, DELETE等', + module VARCHAR(50) NOT NULL COMMENT '操作模块:用户管理、角色管理等', + content TEXT COMMENT '操作内容(可以存储详细的修改信息)', ip VARCHAR(50) COMMENT '操作IP', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (user_id) REFERENCES users(id) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表' + FOREIGN KEY (operator_id) REFERENCES users(id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表'; `; export { operationLogs, role, user, userRole }; diff --git a/src/router/http.ts b/src/router/http.ts index a89fc2b..9c90845 100644 --- a/src/router/http.ts +++ b/src/router/http.ts @@ -7,10 +7,10 @@ import { OkPacket } from 'mysql2'; import { createMathExpr } from "svg-captcha"; import secret from "../config"; import Logger from "../loaders/logger"; +import { getOperator } from "../utils/auth"; import { Message } from "../utils/enums"; import { connection } from "../utils/mysql"; import { logOperation, ModuleType, OperationType } from "../utils/operationLog"; - const utils = require("@pureadmin/utils"); /** 保存验证码 */ @@ -84,11 +84,11 @@ const login = async (req: Request, res: Response) => { if (data.length === 0) { // 记录登录失败日志 logOperation({ - userId: 0, - username: username, + operatorId: 0, // 改为 operatorId + operatorName: username, // 改为 operatorName action: OperationType.LOGIN, module: ModuleType.AUTH, - description: `用户登录失败:用户不存在 (${username})`, + content: `用户登录失败:数据库错误`, // 改为 content ip: req.ip || '' }); @@ -102,15 +102,15 @@ const login = async (req: Request, res: Response) => { // 验证密码 const hashedPassword = createHash("md5").update(password).digest("hex"); if (hashedPassword !== user.password) { - // 记录登录失败日志 - logOperation({ - userId: 0, - username: username, - action: OperationType.LOGIN, - module: ModuleType.AUTH, - description: `用户登录失败:密码错误 (${username})`, - ip: req.ip || '' - }); + // 记录用户不存在日志 + logOperation({ + operatorId: 0, + operatorName: username, + action: OperationType.LOGIN, + module: ModuleType.AUTH, + content: `用户登录失败:用户不存在`, + ip: req.ip || '' + }); return res.json({ success: false, data: { message: "密码错误" } @@ -128,11 +128,11 @@ const login = async (req: Request, res: Response) => { ); // 记录登录成功日志 logOperation({ - userId: user.id, - username: user.username, + operatorId: user.id, + operatorName: user.username, action: OperationType.LOGIN, module: ModuleType.AUTH, - description: `用户登录成功 (${username})`, + content: `用户登录成功 (${username})`, ip: req.ip || '' }); await res.json({ @@ -411,7 +411,10 @@ const updateList = async (req: Request, res: Response) => { // 构建更新字段 const updateFields = []; const updateValues = []; - + + + + // 检查并添加每个可更新字段 if (userData.username) { updateFields.push("username = ?"); @@ -471,16 +474,18 @@ const updateList = async (req: Request, res: Response) => { data: { message: "更新用户失败" } }); } - // 直接使用更新的用户信息记录日志 + const operator = getOperator(req); + // 记录操作日志 logOperation({ - userId: Number(id), // 转换为数字 - username: userData.username || userData.name, // 使用更新的用户信息 - action: OperationType.UPDATE, - module: ModuleType.USER, - description: `更新用户信息:ID=${id}, 字段:${updateFields.join(', ')}`, + operatorId: operator.id, // 使用 decoded 而不是 operator + operatorName: operator.name, // 使用 decoded 而不是 operator + targetId: Number(id), // 被更新用户的ID + targetType: 'user', // 被操作对象类型 + action: OperationType.UPDATE, // 操作类型 + module: ModuleType.USER, // 模块 + content: `更新用户信息:${JSON.stringify(userData)}`, // 操作内容 ip: req.ip || '' }); - // 如果有角色信息,更新用户角色 if (userData.roles && userData.roles.length > 0) { // 先删除原有角色 @@ -590,6 +595,7 @@ const deleteList = async (req: Request, res: Response) => { }); }); } + // 记录删除操作日志 // 提交事务 connection.commit(function(err) { @@ -602,11 +608,23 @@ const deleteList = async (req: Request, res: Response) => { }); }); } + const operator = getOperator(req); + logOperation({ + operatorId: operator.id, + operatorName: operator.name, + targetId: Number(id), + targetType: 'user', + action: OperationType.DELETE, + module: ModuleType.USER, + content: `删除用户:${id}`, + ip: req.ip || '' + }); res.json({ success: true, data: { message: Message[8] } }); }); + }); }); }); diff --git a/src/server.ts b/src/server.ts index 4a00230..e396add 100644 --- a/src/server.ts +++ b/src/server.ts @@ -4,6 +4,7 @@ import * as dayjs from "dayjs"; import * as multer from "multer"; import config from "./config"; import Logger from "./loaders/logger"; +// import { operationLogs, role, user, userRole } from "./models/mysql"; import { importUsersFromLocalExcel } from "./router/excel"; import { getRoleList, getUserList } from "./router/http"; // import { queryTable } from "./utils/mysql"; diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..cbcb6c8 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,26 @@ +import { Request } from "express"; +import * as jwt from "jsonwebtoken"; +import secret from "../config"; + +export interface TokenPayload { + id: number; + username: string; + name: string; +} + +// 获取操作者信息 +export const getOperator = (req: Request): TokenPayload => { + const authHeader = req.get("Authorization"); + if (!authHeader) { + throw new Error("未提供 token"); + } + + const token = authHeader.replace("Bearer ", ""); + const decoded = jwt.verify(token, secret.jwtSecret) as TokenPayload; + + return { + id: decoded.id, + username: decoded.username, + name: decoded.name + }; +}; \ No newline at end of file diff --git a/src/utils/operationLog.ts b/src/utils/operationLog.ts index ef511bb..9d76460 100644 --- a/src/utils/operationLog.ts +++ b/src/utils/operationLog.ts @@ -1,5 +1,5 @@ -import { connection } from "./mysql"; import Logger from "../loaders/logger"; +import { connection } from "./mysql"; // 定义操作类型 export enum OperationType { @@ -21,25 +21,29 @@ export enum ModuleType { // 记录操作日志 export const logOperation = (params: { - userId: number; - username: string; - action: OperationType; - module: ModuleType; - description: string; - ip: string; + operatorId: number; // 操作者ID + operatorName: string; // 操作者名称 + targetId?: number; // 被操作对象ID + targetType?: string; // 被操作对象类型 + action: OperationType; // 操作类型(使用枚举) + module: ModuleType; // 模块(使用枚举) + content: string; // 操作内容 + ip: string; // IP地址 }) => { const sql = ` INSERT INTO operation_logs - (user_id, username, action, module, description, ip) - VALUES (?, ?, ?, ?, ?, ?) + (operator_id, operator_name, target_id, target_type, action, module, content, ip) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) `; const values = [ - params.userId, - params.username, + params.operatorId, + params.operatorName, + params.targetId || null, + params.targetType || null, params.action, params.module, - params.description, + params.content, params.ip ];