log记录完善

This commit is contained in:
pipipigua 2024-10-31 21:19:37 +08:00
parent e45c367e15
commit 75e663f74e
5 changed files with 95 additions and 44 deletions

View File

@ -44,17 +44,19 @@ const userRole = `
/** 创建操作日志表 */ /** 创建操作日志表 */
const operationLogs = ` const operationLogs = `
CREATE TABLE IF NOT EXISTS operation_logs ( CREATE TABLE IF NOT EXISTS operation_logs (
id INT PRIMARY KEY AUTO_INCREMENT, id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL, operator_id INT NOT NULL COMMENT '操作者ID',
username VARCHAR(255), operator_name VARCHAR(100) NOT NULL COMMENT '操作者名称',
action VARCHAR(255) NOT NULL COMMENT '操作类型:新增、修改、删除等', target_id INT COMMENT '被操作对象ID',
module VARCHAR(255) NOT NULL COMMENT '操作模块:用户管理、角色管理等', target_type VARCHAR(50) COMMENT '被操作对象类型user, role等',
description TEXT COMMENT '操作详细描述', action VARCHAR(50) NOT NULL COMMENT '操作类型CREATE, UPDATE, DELETE等',
module VARCHAR(50) NOT NULL COMMENT '操作模块:用户管理、角色管理等',
content TEXT COMMENT '操作内容(可以存储详细的修改信息)',
ip VARCHAR(50) COMMENT '操作IP', ip VARCHAR(50) COMMENT '操作IP',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) FOREIGN KEY (operator_id) REFERENCES users(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';
`; `;
export { operationLogs, role, user, userRole }; export { operationLogs, role, user, userRole };

View File

@ -7,10 +7,10 @@ import { OkPacket } from 'mysql2';
import { createMathExpr } from "svg-captcha"; import { createMathExpr } from "svg-captcha";
import secret from "../config"; import secret from "../config";
import Logger from "../loaders/logger"; import Logger from "../loaders/logger";
import { getOperator } from "../utils/auth";
import { Message } from "../utils/enums"; import { Message } from "../utils/enums";
import { connection } from "../utils/mysql"; import { connection } from "../utils/mysql";
import { logOperation, ModuleType, OperationType } from "../utils/operationLog"; import { logOperation, ModuleType, OperationType } from "../utils/operationLog";
const utils = require("@pureadmin/utils"); const utils = require("@pureadmin/utils");
/** 保存验证码 */ /** 保存验证码 */
@ -84,11 +84,11 @@ const login = async (req: Request, res: Response) => {
if (data.length === 0) { if (data.length === 0) {
// 记录登录失败日志 // 记录登录失败日志
logOperation({ logOperation({
userId: 0, operatorId: 0, // 改为 operatorId
username: username, operatorName: username, // 改为 operatorName
action: OperationType.LOGIN, action: OperationType.LOGIN,
module: ModuleType.AUTH, module: ModuleType.AUTH,
description: `用户登录失败:用户不存在 (${username})`, content: `用户登录失败:数据库错误`, // 改为 content
ip: req.ip || '' ip: req.ip || ''
}); });
@ -102,15 +102,15 @@ const login = async (req: Request, res: Response) => {
// 验证密码 // 验证密码
const hashedPassword = createHash("md5").update(password).digest("hex"); const hashedPassword = createHash("md5").update(password).digest("hex");
if (hashedPassword !== user.password) { if (hashedPassword !== user.password) {
// 记录登录失败日志 // 记录用户不存在日志
logOperation({ logOperation({
userId: 0, operatorId: 0,
username: username, operatorName: username,
action: OperationType.LOGIN, action: OperationType.LOGIN,
module: ModuleType.AUTH, module: ModuleType.AUTH,
description: `用户登录失败:密码错误 (${username})`, content: `用户登录失败:用户不存在`,
ip: req.ip || '' ip: req.ip || ''
}); });
return res.json({ return res.json({
success: false, success: false,
data: { message: "密码错误" } data: { message: "密码错误" }
@ -128,11 +128,11 @@ const login = async (req: Request, res: Response) => {
); );
// 记录登录成功日志 // 记录登录成功日志
logOperation({ logOperation({
userId: user.id, operatorId: user.id,
username: user.username, operatorName: user.username,
action: OperationType.LOGIN, action: OperationType.LOGIN,
module: ModuleType.AUTH, module: ModuleType.AUTH,
description: `用户登录成功 (${username})`, content: `用户登录成功 (${username})`,
ip: req.ip || '' ip: req.ip || ''
}); });
await res.json({ await res.json({
@ -411,7 +411,10 @@ const updateList = async (req: Request, res: Response) => {
// 构建更新字段 // 构建更新字段
const updateFields = []; const updateFields = [];
const updateValues = []; const updateValues = [];
// 检查并添加每个可更新字段 // 检查并添加每个可更新字段
if (userData.username) { if (userData.username) {
updateFields.push("username = ?"); updateFields.push("username = ?");
@ -471,16 +474,18 @@ const updateList = async (req: Request, res: Response) => {
data: { message: "更新用户失败" } data: { message: "更新用户失败" }
}); });
} }
// 直接使用更新的用户信息记录日志 const operator = getOperator(req);
// 记录操作日志
logOperation({ logOperation({
userId: Number(id), // 转换为数字 operatorId: operator.id, // 使用 decoded 而不是 operator
username: userData.username || userData.name, // 使用更新的用户信息 operatorName: operator.name, // 使用 decoded 而不是 operator
action: OperationType.UPDATE, targetId: Number(id), // 被更新用户的ID
module: ModuleType.USER, targetType: 'user', // 被操作对象类型
description: `更新用户信息:ID=${id}, 字段:${updateFields.join(', ')}`, action: OperationType.UPDATE, // 操作类型
module: ModuleType.USER, // 模块
content: `更新用户信息:${JSON.stringify(userData)}`, // 操作内容
ip: req.ip || '' ip: req.ip || ''
}); });
// 如果有角色信息,更新用户角色 // 如果有角色信息,更新用户角色
if (userData.roles && userData.roles.length > 0) { if (userData.roles && userData.roles.length > 0) {
// 先删除原有角色 // 先删除原有角色
@ -590,6 +595,7 @@ const deleteList = async (req: Request, res: Response) => {
}); });
}); });
} }
// 记录删除操作日志
// 提交事务 // 提交事务
connection.commit(function(err) { 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({ res.json({
success: true, success: true,
data: { message: Message[8] } data: { message: Message[8] }
}); });
}); });
}); });
}); });
}); });

View File

@ -4,6 +4,7 @@ import * as dayjs from "dayjs";
import * as multer from "multer"; import * as multer from "multer";
import config from "./config"; import config from "./config";
import Logger from "./loaders/logger"; import Logger from "./loaders/logger";
// import { operationLogs, role, user, userRole } from "./models/mysql";
import { importUsersFromLocalExcel } from "./router/excel"; import { importUsersFromLocalExcel } from "./router/excel";
import { getRoleList, getUserList } from "./router/http"; import { getRoleList, getUserList } from "./router/http";
// import { queryTable } from "./utils/mysql"; // import { queryTable } from "./utils/mysql";

26
src/utils/auth.ts Normal file
View File

@ -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
};
};

View File

@ -1,5 +1,5 @@
import { connection } from "./mysql";
import Logger from "../loaders/logger"; import Logger from "../loaders/logger";
import { connection } from "./mysql";
// 定义操作类型 // 定义操作类型
export enum OperationType { export enum OperationType {
@ -21,25 +21,29 @@ export enum ModuleType {
// 记录操作日志 // 记录操作日志
export const logOperation = (params: { export const logOperation = (params: {
userId: number; operatorId: number; // 操作者ID
username: string; operatorName: string; // 操作者名称
action: OperationType; targetId?: number; // 被操作对象ID
module: ModuleType; targetType?: string; // 被操作对象类型
description: string; action: OperationType; // 操作类型(使用枚举)
ip: string; module: ModuleType; // 模块(使用枚举)
content: string; // 操作内容
ip: string; // IP地址
}) => { }) => {
const sql = ` const sql = `
INSERT INTO operation_logs INSERT INTO operation_logs
(user_id, username, action, module, description, ip) (operator_id, operator_name, target_id, target_type, action, module, content, ip)
VALUES (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`; `;
const values = [ const values = [
params.userId, params.operatorId,
params.username, params.operatorName,
params.targetId || null,
params.targetType || null,
params.action, params.action,
params.module, params.module,
params.description, params.content,
params.ip params.ip
]; ];