1. 前言
在我们日常开发系统的安全架构中,仅仅通过认证和授权往往不足以满足合规、溯源、风险预警等需求。企业级系统必须记录并分析 “谁在什么时候对什么资源做了什么操作”,并结合规则引擎识别异常行为,及时告警。
安全审计作为企业防护的最后一道防线,能有效追踪异常行为、还原攻击链、满足合规要求。本文笔者将带领大家基于 Spring Security 构建完整的安全审计系统,实现关键操作追踪与实时风险预警。
2. Spring Security 审计架构设计
2.1 系统架构
我们常见的安全审计应该具备以下基础:以笔者目前所在公司使用的系统架构如下图:
安全日志与审计:关键操作追踪与风险预警-1.png)
2.2 审计日志四要素
| 要素 | 说明 | 示例 |
|---|---|---|
| 主体 | 操作执行者 | 用户 ID、IP 地址 |
| 客体 | 被操作对象 | 数据 ID、接口路径 |
| 动作 | 操作类型 | 登录、删除、授权变更 |
| 环境 | 操作上下文 | 时间、设备、地理位置 |
2.3 技术栈选择
- 事件采集:Spring AOP + ApplicationEvent
- 存储方案:MySQL + MyBatis‑Plus(中小型应用适用)或 Elasticsearch + Logstash(大型应用 + 实时检索)
- 风险分析:Drools 规则引擎
- 可视化:Grafana 监控看板
笔者为简化演示,本文以 MySQL + MyBatis‑Plus 为存储方案。
鉴于之前的子模块代码中,我们已经集成好了 MySQL + MyBatis‑Plus,在开始之前复用之前的子模块,需在 pom.xml 中引入:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>9.44.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.74.1.Final</version>
</dependency>3. 数据库与实体设计
CREATE TABLE audit_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
action VARCHAR(100),
resource VARCHAR(200),
timestamp DATETIME,
duration BIGINT
);@Data
@TableName("audit_log")
public class AuditLog {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String action;
private String resource;
private LocalDateTime timestamp;
private Long duration;
}
// Mapper
@Mapper
public interface AuditLogMapper extends BaseMapper<AuditLog> {}4. 事件采集:Spring AOP + 自定义注解
4.1 自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Audit {
String action();
String resource();
}4.2 AOP 切面实现
@Aspect
@Component
public class AuditAspect {
@Autowired
private ApplicationEventPublisher publisher;
@Pointcut("@annotation(audit)")
public void auditPoint(Audit audit) {}
@Around("auditPoint(audit)")
public Object around(ProceedingJoinPoint jp, Audit audit) throws Throwable {
long start = System.currentTimeMillis();
Object result = jp.proceed();
long duration = System.currentTimeMillis() - start;
MethodSignature ms = (MethodSignature) jp.getSignature();
String username = ((UserDetails) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal()).getUsername();
AuditEvent evt = new AuditEvent(username, audit.action(), audit.resource(), duration, LocalDateTime.now());
publisher.publishEvent(evt);
return result;
}
}说明:上述代码中,可补充捕获异常并发布失败事件。
4.3 事件类
public record AuditEvent(String username, String action,
String resource, long duration,
LocalDateTime timestamp) {}4.4 事件监听并保存日志
@Component
@RequiredArgsConstructor
public class AuditListener {
private final AuditLogMapper mapper;
private final KieContainer kieContainer;
private final Counter riskCounter; // Prometheus counter
@EventListener
public void handle(AuditEvent evt) {
AuditLog log = new AuditLog(null, evt.username(),
evt.action(), evt.resource(),
evt.timestamp(), evt.duration());
mapper.insert(log);
var session = kieContainer.newKieSession();
session.insert(log);
var fired = session.fireAllRules();
session.dispose();
if (fired > 0) riskCounter.increment();
}
}5. Drools 动态规则引擎
5.1 Drools 配置
@Configuration
public class DroolsConfig {
@Bean
public KieContainer kieContainer() {
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
kfs.write(ResourceFactory.newClassPathResource("rules/audit-risk.drl"));
ks.newKieBuilder(kfs).buildAll();
return ks.newKieContainer(
ks.getRepository().getDefaultReleaseId());
}
}5.2 规则文件 audit-risk.drl
rule "Slow Audit"
when
$log: AuditLog(duration > 1000)
then
System.out.println("风险预警:操作耗时过长 by " + $log.getUsername());
end6. 监控指标采集与可视化
6.1 添加监控依赖并启用 Actuator
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>6.2 配置 application.yml
management:
endpoints:
web:
exposure:
include: prometheus,health6.3 指标配置
@Configuration
public class MetricsConfig {
@Bean
public Counter riskCounter(MeterRegistry reg) {
return Counter.builder("audit.risk.count")
.description("Number of risky audit events")
.register(reg);
}
}Prometheus 采集 /actuator/prometheus,Grafana 仪表板配置查询:audit_risk_count。
7. 控制器示例
完成上述所有操作后,可编写一个 Controller 进行相关测试:
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class DemoController {
@Audit(action = "ACCESS", resource = "demoEndpoint")
@GetMapping("/demo")
public String demo() {
return "OK";
}
}8. 结语
本章节我们以最简单的一个入门示例,主要讲解了:
- 利用 MyBatis‑Plus 实现高效、自动化地操作 MySQL 审计日志表;
- 通过 Spring AOP + ApplicationEvent 实现操作日志透明采集;
- 使用 Drools 规则引擎实现可配置、实时化的风险判断;
- 集成 Prometheus + Grafana 实现可视化监控,从流量、耗时、风险事件维度全方位审计系统行为。
这套方案可按需扩展为审计超级系统,支持敏感操作追踪、异常报警、人机判定等功能,适合企业级复杂场景。后续可添加 CI/CD 自动部署 Drools 规则、Grafana 警报等高级功能。
