1. 前言

在我们日常开发系统的安全架构中,仅仅通过认证和授权往往不足以满足合规、溯源、风险预警等需求。企业级系统必须记录并分析 “谁在什么时候对什么资源做了什么操作”,并结合规则引擎识别异常行为,及时告警。

安全审计作为企业防护的最后一道防线,能有效追踪异常行为、还原攻击链、满足合规要求。本文笔者将带领大家基于 Spring Security 构建完整的安全审计系统,实现关键操作追踪与实时风险预警。

2. Spring Security 审计架构设计

2.1 系统架构

我们常见的安全审计应该具备以下基础:以笔者目前所在公司使用的系统架构如下图:

安全审计系统架构图

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 中引入:

1
2
3
4
5
6
7
8
9
10
<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. 数据库与实体设计

1
2
3
4
5
6
7
8
CREATE TABLE audit_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
action VARCHAR(100),
resource VARCHAR(200),
timestamp DATETIME,
duration BIGINT
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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 自定义注解

1
2
3
4
5
6
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Audit {
String action();
String resource();
}

4.2 AOP 切面实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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 事件类

1
2
3
public record AuditEvent(String username, String action,
String resource, long duration,
LocalDateTime timestamp) {}

4.4 事件监听并保存日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@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 配置

1
2
3
4
5
6
7
8
9
10
11
12
@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

1
2
3
4
5
6
rule "Slow Audit"
when
$log: AuditLog(duration > 1000)
then
System.out.println("风险预警:操作耗时过长 by " + $log.getUsername());
end

6. 监控指标采集与可视化

6.1 添加监控依赖并启用 Actuator

1
2
3
4
5
6
7
8
<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

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: prometheus,health

6.3 指标配置

1
2
3
4
5
6
7
8
9
@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/prometheusGrafana 仪表板配置查询:audit_risk_count

7. 控制器示例

完成上述所有操作后,可编写一个 Controller 进行相关测试:

1
2
3
4
5
6
7
8
9
10
@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 警报等高级功能。

如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给笔者一点点鼓励!