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

<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());
end

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

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,health

6.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/prometheusGrafana 仪表板配置查询: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 警报等高级功能。

最后修改:2026 年 03 月 12 日
如果觉得我的文章对你有用,请随意赞赏