本文目录导读:

- 核心原则
- 方案一:后端 AOP 切面记录(最推荐,Java/Spring Boot 示例)
- 方案二:数据库触发器 + 审计表(适合数据变更审计)
- 方案三:前端拦截器记录(适用于 SPA 单页应用)
- 方案四:Linux 用户操作审计(服务器运维)
- 最佳实践总结 & 脚本选择建议
- 重要提醒
记录操作日志是软件开发中非常关键的安全和审计手段,根据你的技术栈(前端、后端、数据库)和具体需求,实现方式有所不同。
以下是从简单到复杂、从前端到后端的几种主流实现方案,并附上具体脚本示例。
核心原则
在写脚本前,需明确要记录什么(5W1H原则):
- Who:谁操作的(用户ID/IP)
- What:做了什么(增删改查、具体数据)
- When:操作时间
- Where:操作的模块/功能/API路径
- Why/How:请求参数、结果、耗时
后端 AOP 切面记录(最推荐,Java/Spring Boot 示例)
这是最标准、侵入性最低的方式,利用AOP(Aspect Oriented Programming)拦截所有Controller方法,自动记录。
步骤:
- 自定义注解
@Log:标记哪些方法需要记录。 - 切面类
LogAspect:在方法执行前后织入代码。
注解定义
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String module() default ""; // 模块名称
String operation() default ""; // 操作类型: 添加/删除/修改/查询
}
切面类脚本(核心)
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
@Aspect
@Component
public class LogAspect {
@Around("@annotation(com.example.demo.Log)") // 指定切点
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = null;
boolean isException = false;
String errorMsg = null;
try {
// 执行目标方法
result = joinPoint.proceed();
} catch (Throwable e) {
isException = true;
errorMsg = e.getMessage();
throw e; // 继续抛异常,不吞掉
} finally {
// 无论成功失败,都记录日志
recordLog(joinPoint, startTime, result, isException, errorMsg);
}
return result;
}
private void recordLog(ProceedingJoinPoint joinPoint, long startTime, Object result, boolean isException, String errorMsg) {
try {
// 1. 获取请求信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 2. 获取注解上的信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Log logAnnotation = signature.getMethod().getAnnotation(Log.class);
// 3. 组装日志对象 (这里直接打印,实际应存入数据库或文件)
System.out.println("====== 操作日志开始 ======");
System.out.println("时间: " + LocalDateTime.now());
System.out.println("IP: " + request.getRemoteAddr());
System.out.println("URL: " + request.getRequestURI());
System.out.println("模块: " + logAnnotation.module());
System.out.println("操作: " + logAnnotation.operation());
System.out.println("用户ID: " + request.getHeader("userId")); // 从请求头获取当前用户
System.out.println("请求参数: " + Arrays.toString(joinPoint.getArgs()));
System.out.println("执行耗时(ms): " + (System.currentTimeMillis() - startTime));
System.out.println("是否异常: " + isException);
if (isException) System.out.println("异常信息: " + errorMsg);
System.out.println("====== 操作日志结束 ======");
// TODO: 将 logInfo 存入数据库 (异步执行,避免影响主业务)
} catch (Exception e) {
// 日志记录本身不能抛出异常,避免影响业务
System.err.println("记录操作日志失败: " + e.getMessage());
}
}
}
用法: 在Controller方法上添加注解即可。
@RestController
public class UserController {
@PostMapping("/user/add")
@Log(module = "用户管理", operation = "新增用户")
public Result addUser(@RequestBody User user) {
// 业务逻辑
return Result.success();
}
}
数据库触发器 + 审计表(适合数据变更审计)
不依赖业务代码,直接在数据库层面记录对某张表的更改。
缺点: 只能记录INSERT/UPDATE/DELETE,无法记录“查询”和“用户登录”等行为。
MySQL 示例:记录用户表 users 的变更
-- 1. 创建日志表
CREATE TABLE `audit_log` (
`id` int NOT NULL AUTO_INCREMENT,
`table_name` varchar(50) DEFAULT NULL,
`operation` varchar(10) DEFAULT NULL, -- INSERT, UPDATE, DELETE
`old_data` json DEFAULT NULL, -- 旧数据
`new_data` json DEFAULT NULL, -- 新数据
`operator` varchar(50) DEFAULT NULL, -- 操作人 (需应用传入)
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- 2. 创建触发器 (UPDATE 为例)
DELIMITER $$
CREATE TRIGGER `users_audit_update`
AFTER UPDATE ON `users`
FOR EACH ROW
BEGIN
INSERT INTO `audit_log` (`table_name`, `operation`, `old_data`, `new_data`, `operator`)
VALUES (
'users',
'UPDATE',
JSON_OBJECT('id', OLD.id, 'name', OLD.name, 'email', OLD.email),
JSON_OBJECT('id', NEW.id, 'name', NEW.name, 'email', NEW.email),
@current_user -- 需要应用程序在执行 SQL 前设置 SET @current_user = '张三';
);
END$$
DELIMITER ;
注意: 触发器无法自动感知Who,需在应用层执行SQL前设置会话变量(如 SET @current_user = ‘admin’;)。
前端拦截器记录(适用于 SPA 单页应用)
主要用于记录页面行为(点击、路由跳转、按钮点击)。
Vue.js 示例(使用路由守卫 + Axios 拦截器)
// 1. 路由守卫:记录页面跳转
router.beforeEach((to, from, next) => {
const logInfo = {
type: 'ROUTE_CHANGE',
from: from.fullPath,
to: to.fullPath,
time: new Date().toISOString(),
user: store.state.userInfo?.username
};
// 发送到后端 (使用 navigator.sendBeacon 确保页面卸载时也能发送)
navigator.sendBeacon('/api/log/operate', JSON.stringify(logInfo));
next();
});
// 2. Axios 响应拦截器:记录 API 请求结果(增删改操作)
axios.interceptors.response.use(
response => {
// 如果请求是 POST/PUT/DELETE,记录操作
if (['post', 'put', 'delete'].includes(response.config.method)) {
recordApiLog(response.config, response.data);
}
return response;
},
error => {
// 记录失败的请求
recordApiLog(error.config, { status: error.status, message: error.message });
return Promise.reject(error);
}
);
function recordApiLog(config, responseData) {
const log = {
type: 'API_CALL',
method: config.method.toUpperCase(),
url: config.url,
params: config.params || config.data,
status: responseData?.status || responseData?.code,
time: new Date().toISOString()
};
// 异步发送(不阻塞主流程)
fetch('/api/log/operate', { method: 'POST', body: JSON.stringify(log), keepalive: true });
}
Linux 用户操作审计(服务器运维)
记录谁登录了服务器,执行了什么命令。
使用 history + 系统日志
# 在 /etc/profile 或 ~/.bashrc 中添加如下脚本
export HISTTIMEFORMAT="%F %T "
export PROMPT_COMMAND='\
if [ -z "$OLD_PWD" ];then
OLD_PWD=$PWD
fi
if [ ! -z "$LAST_CMD" ]; then
logger -p local1.notice -t bash_history "[USER=$USER] [PWD=$OLD_PWD] [CMD=$LAST_CMD]"
fi
LAST_CMD=$(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//") '
使用 auditd(Linux 审计系统,更专业)
# 1. 安装 sudo apt install auditd audispd-plugins -y # 2. 添加规则:监控 /etc/passwd 文件的写入 sudo auditctl -w /etc/passwd -p wa -k password_change # 3. 查看日志 sudo ausearch -k password_change | aureport -f
最佳实践总结 & 脚本选择建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 业务系统操作 (增删改查) | AOP切面 (方案一) | 低侵入,解耦,可记录详细业务上下文。 |
| 数据库敏感表审计 | 数据库触发器 (方案二) | 无法被应用日志绕过,安全性高,适合合规要求。 |
| 用户界面行为分析 | 前端拦截器 (方案三) | 记录页面停留时间、按钮点击率等。 |
| 服务器安全审计 | auditd 或日志脚本 (方案四) | 操作系统级别,监控所有命令执行。 |
重要提醒
- 异步处理:写日志不要阻塞主业务流程(使用MQ、线程池或异步写入)。
- 日志脱敏:记录参数时,密码、身份证、Token等敏感字段要处理。
- 保留期限:设计日志表时加
expire_time字段,定期归档或删除。 - 日志存储:高并发场景建议用 ElasticSearch 存储,用 Logstash 或 Filebeat 收集,而不是直接写数据库。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播