Philani50/fraud-detection-engine-

GitHub: Philani50/fraud-detection-engine-

一个基于 Spring Boot 的生产级金融欺诈检测微服务,通过可配置的规则引擎对交易进行实时风险评估并生成告警。

Stars: 0 | Forks: 0

# 欺诈检测引擎 一个生产级的 Spring Boot 微服务,可针对可配置的欺诈检测规则集实时评估金融交易。警报会被持久化,可通过 Prometheus 指标进行监控,并受 OAuth2 JWT 身份验证保护。 ## 目录 - [概述](#overview) - [架构](#architecture) - [欺诈规则](#fraud-rules) - [代码指南 — 每个类的功能](#code-guide--what-each-class-does) - [技术栈](#tech-stack) - [项目结构](#project-structure) - [入门指南](#getting-started) - [API 参考](#api-reference) - [配置](#configuration) - [安全性](#security) - [数据库](#database) - [可观测性](#observability) - [测试](#testing) ## 概述 欺诈检测引擎通过 REST 接收交易 payload,保存该交易,根据所有已启用的欺诈规则对其进行评估,持久化生成的警报,并将评估结果返回给调用者。 规则可以通过配置独立启用或禁用,可以独立隔离测试,并遵循开闭原则 — 添加新规则只需新建一个类,无需对现有代码进行任何改动。 ## 架构 ``` POST /v1/fraud/evaluations │ ▼ FraudController │ maps request → TransactionEntity (MapStruct) │ saves transaction ▼ FraudEvaluationService │ builds RuleContext (memoised client profile, DB-backed queries) │ iterates List in @Order sequence │ for each enabled + applicable rule → evaluate() │ persists alerts via FraudPersistenceService │ increments Micrometer counters + records Timer ▼ FraudAlertEntity (Flyway-managed PostgreSQL / H2 for local) ``` ### 关键设计决策 | 决策 | 理由 | |---|---| | `RuleContext` 普通对象(非 Spring bean) | 按请求创建;持有一个备忘录模式的 `clientProfileSupplier`,因此无论有多少规则调用 `getClientProfile()`,每次评估最多只会访问一次数据库 | | 不向规则传递原始的 `List` | 所有时间窗口查询都委托给建立了索引的数据库方法 — 防止 O(n) 内存陷阱 | | `FraudAlertEntity` 上的 `@Builder.Default status = PENDING` | 确保警报状态永不为 null,而无需依赖无参构造函数的副作用 | | 使用 AES-256-GCM 加密 PII 字段 | 认证加密可防止密文被篡改;每次加密调用都会生成随机的 12 字节 IV | | 选择 Flyway 而非 `ddl-auto` | Schema 迁移在所有环境中均具有版本控制、可审计且可重现 | ## 欺诈规则 系统内置了六条规则。默认全部启用,并且可以独立控制开关。 | 规则 | 代码 | 严重性 | 触发条件 | |---|---|---|---| | 长期结构化拆分 | `RULE-001` | HIGH | 24 小时内发生 3 笔或以上低于 10,000 兰特的现金交易,且总额 ≥ 10,000 兰特 | | 资料变更后大额交易 | `RULE-002` | CRITICAL | 在 PII 资料更新后的 48 小时内,发生金额 ≥ 50,000 兰特的交易 | | 可疑消费行为 | `RULE-003` | MEDIUM | 交易金额超过客户月平均收入的 300% | | 交易频率激增 | `RULE-004` | HIGH | 同一客户在过去 1 小时内发生 10 笔或以上交易 | | 整数金额模式 | `RULE-005` | MEDIUM | 24 小时内发生 3 笔或以上金额可被 1,000 兰特整除的交易 | | 高风险快速转移 | `RULE-006` | CRITICAL | 在 30 分钟内,汇出转账/取款金额 ≥ 20,000 兰特入金存款的 80% | ## 代码指南 — 每个类的功能 本节用通俗的语言解释每一个类,以便您在无需具备框架先备知识的情况下也能浏览代码库。 ### 入口点 #### `Application.java` 整个服务的起点。当您运行应用程序时,Java 会调用此类中的 `main` 方法。它会指示 Spring Boot 启动并自动加载所有其他类。 ### 控制器 — “正门” 控制器是接收来自外部世界(例如 Postman 或其他服务)HTTP 请求的类。 #### `FraudController.java` 处理主端点 `POST /v1/fraud/evaluations`。当一笔交易传入时: 1. 验证请求字段 2. 将其转换为数据库对象 3. 保存该对象 4. 将其发送给欺诈评估引擎 5. 返回结果(触发了哪些规则,创建了哪些警报) #### `ServiceController.java` 处理 `GET /api/v1/health`。返回一条简单的“服务已上线”消息。供监控工具检查应用程序是否正在运行。无需身份验证。 ### 服务层 — “大脑” 服务包含业务逻辑。它们位于控制器和数据库之间。 #### `FraudEvaluationService.java` 一个接口(契约),声明:“实现我的类必须拥有一个 `evaluate` 方法,该方法接收一笔交易并返回一个警报列表。”这使得代码更容易替换或测试。 #### `FraudEvaluationServiceImpl.java` `FraudEvaluationService` 的实际实现。这是编排器 — 它负责: 1. 为交易构建一个 `RuleContext` 2. 循环遍历所有 6 条欺诈规则 3. 跳过已禁用或不适用的规则 4. 对每条适用的规则调用 `evaluate()` 5. 保存所有生成的警报 6. 记录计时指标并记录所有日志 ### 欺诈规则 — “侦探” 每条欺诈规则都是一个独立的类。它们都实现了相同的 `FraudRule` 接口,以便引擎可以统一对待它们。 #### `FraudRule.java` 每条规则都必须遵循的接口(蓝图)。它定义了每条规则必须回答的三个问题: - `isEnabled()` — 这条规则是否应该运行? - `isApplicable(transaction)` — 这条规则与这种类型的交易相关吗? - `evaluate(transaction, context)` — 这笔交易看起来可疑吗? #### `StructuringRule.java` — RULE-001 检测结构化拆分:一种某人进行多笔小额现金存款以避免触发大额交易警报的模式。当 24 小时内发生 3 笔或以上低于 10,000 兰特且总额达到 10,000 兰特以上的存款时触发。 #### `ProfileChangeRule.java` — RULE-002 标记在客户个人资料更新后不久发生的大额交易。资料变更后紧接着进行大额转账是一种常见的欺诈模式。 #### `SuspiciousSpendRule.java` — RULE-003 将交易金额与客户的月平均收入进行比较。如果某人在一笔交易中的支出超过其月收入的 3 倍,则会被标记。 #### `VelocityRule.java` — RULE-004 检测异常快速的交易活动。如果客户在一小时内进行 10 笔或更多交易,则会触发 — 这可能表明存在自动化攻击或账户被盗用。 #### `RoundAmountRule.java` — RULE-005 寻找具有可疑整数金额(例如 5,000 兰特、10,000 兰特、2,000 兰特)的交易模式。合法购买极少会以精确的千位整数结尾。 #### `RapidMovementRule.java` — RULE-006 检测“快进快出”的资金流动:大额存款后迅速提取大部分相同资金。这是一种典型的洗钱模式。 ### 规则工具 — “助手” #### `RuleContext.java` 为每次交易评估全新创建的辅助对象。它为规则提供了安全、高效的数据库数据(近期交易、客户资料)访问权限,而无需每个规则直接查询数据库。重要的是,客户资料只会获取一次 — 即使多个规则请求它。 #### `RuleContextFactory.java` 负责构建 `RuleContext`。它连接数据库连接和备忘录模式的资料查找功能,以便将准备就绪的 `RuleContext` 交给每个规则使用。 #### `FraudAlertFactory.java` 一个以一致方式构建 `FraudAlertEntity`(警报的数据库记录)的工厂。每个规则都使用它而不是手动构建警报,从而确保它们具有相同的外观。 #### `TimeWindowCalculator.java` 一个用于计算时间边界的小助手。例如,“整整 24 小时前的时间是多少?”规则使用它来定义其回溯窗口,而无需每个规则重复编写相同的日期算术。 ### 持久层 — “数据库层” 这些类处理与保存和加载数据相关的所有事情。 #### `FraudPersistenceService.java` 应用程序和数据库之间的唯一联系点。所有交易、客户资料和欺诈警报的读写都通过此类进行。它处理错误日志记录,并将数据库异常包装为有意义的领域错误。 #### `TransactionEntity.java` 表示 `transaction` 数据库表中的一行。每个字段映射到一个列。这就是新交易传入时保存的内容。 #### `ClientProfileEntity.java` 表示 `client_profile` 表中的一行。包含有关客户的个人详细信息 — 姓名、身份证号、平均收入、风险评级等。`fullName` 和 `idNumber` 字段在保存前会自动加密,在加载时自动解密。 #### `FraudAlertEntity.java` 表示 `fraud_alert` 表中的一行。存储规则触发时的结果 — 触发了哪条规则、风险评分是多少、详细信息是什么以及当前状态(PENDING、UNDER_REVIEW 等)。 #### `PpiChangeRecord.java` 嵌入在 `ClientProfileEntity` 中的子记录。每当客户的个人详细信息发生更改时,都会在此处添加一条记录,跟踪更改的内容、时间以及旧值是什么。旧值和新值也会被加密。 #### `TransactionRepository.java` 提供交易的数据库查询方法。例如:“查找过去一小时内该客户的所有交易”或“计算该客户今天的交易数量”。 #### `ClientProfileRepository.java` 提供客户资料的数据库查询方法。例如:“查找客户 ID 为 X 的资料。” #### `FraudAlertRepository.java` 提供欺诈警报的数据库访问 — 在保存新生成的警报时使用。 #### `EncryptedStringConverter.java` 一个位于应用程序和数据库之间的隐形助手。每当保存敏感文本字段(如姓名或身份证号)时,此类会自动将其加密。当重新加载时,此类会自动将其解密。使用它的规则或服务完全无需关心加密过程。 ### 安全 — “锁” #### `FieldEncryptionService.java` 定义了两个操作的接口:`encrypt` 和 `decrypt`。将接口与实现分离使得在需要时可以轻松更换加密算法。 #### `AesGcmFieldEncryptionService.java` 实际的加密实现。使用 AES-256-GCM,这是一种现代认证加密标准。每次加密调用都会生成一个新的随机 IV(初始化向量),因此相同的数据永远不会产生两次相同的密文。 #### `SecurityConfig.java` 配置哪些端点需要身份验证,哪些是公开的。设置 OAuth2 JWT 资源服务器,以便传入请求必须包含由配置的身份提供者签名的有效 JWT token。同时启用控制器方法上的 `@PreAuthorize` 注解。 ### 适配器 — “外部调用” 适配器包处理与此应用程序外部的外部服务的通信。 #### `ClientProfileAdapter.java` 定义了一个操作的接口:`fetchProfile(clientId)`。任何从外部服务获取客户资料的类都必须实现此接口。 #### `ClientProfileAdapterImpl.java` 真正的实现。它调用外部的 CRM 或核心银行服务以获取客户资料。它装饰有: - **CircuitBreaker** — 如果外部服务宕机,在重复失败后停止调用它 - **TimeLimiter** — 如果调用耗时超过 3 秒,则取消该调用 - **Bulkhead** — 限制同时进行的飞行调用数量 - **Cache** — 如果最近获取过同一客户的资料,则返回缓存副本,而不是再次调用外部服务 如果外部服务失败,它会优雅地回退并返回空结果 — 引擎将继续使用不需要该资料的规则进行评估。 #### `ClientProfileProxyClient.java` 声明式 HTTP 客户端。该接口声明了端点(`GET /v1/clients/{clientId}/profile`),Spring 会自动生成实现,而无需编写原始 HTTP 代码。 #### `ClientProfileProxyConfig.java` 配置 HTTP 客户端 — 设置基本 URL、超时、`X-Channel-Source` 标头以及针对 401 Unauthorized 响应的错误处理器。 #### `ClientProfileProperties.java` 保存外部服务 URL 和超时设置的配置记录。值来自 `application.yml`,可以通过环境变量覆盖。 #### `ClientProfileResponse.java` 一个表示来自外部客户资料服务的 JSON 响应的记录(不可变数据对象)。字段包括客户 ID、全名、身份证号、收入和风险评级。 ### 映射器 — “翻译器” 映射器在不同对象类型之间进行转换,以保持其余代码的整洁。 #### `FraudMapper.java` 在 API 层和数据库层之间进行转换: - 将传入的 `FraudEvaluationRequest`(来自 API)转换为 `TransactionEntity`(用于数据库) - 将 `FraudAlertEntity`(来自数据库)转换为 `FraudAlertResponse`(用于 API 响应) - 构建返回给调用者的完整 `FraudEvaluationResponse` #### `ClientProfileMapper.java` 将 `ClientProfileResponse`(来自外部服务)转换为 `ClientProfileEntity`(规则使用的内部表示)。 ### 模型 — “数据形态” 这些是简单的数据容器 — 它们定义了进出 API 的数据形态。 #### `FraudEvaluationRequest.java` 定义调用者在提交交易进行评估时必须发送的内容。字段包括账户 ID、客户 ID、金额、币种、交易类型渠道和时间戳。所有必填字段在处理请求前都会进行验证。 #### `FraudEvaluationResponse.java` 定义调用者在评估后收到的内容。包括交易 ID、客户 ID、生成的警报计数以及完整的警报详细信息列表。 #### `FraudAlertResponse.java` 响应中单个警报的数据形态。包括规则代码、规则名称、风险评分、严重性、状态、详细信息及其创建时间。 #### `ErrorResponse.java` 错误响应的标准形态。每当出现问题时(验证失败、服务器错误等),响应体都会遵循此结构,包含状态码、错误类型、消息、时间戳和关联 ID。 ### 异常处理 — “错误管理者” #### `BusinessException.java` 所有预期业务错误的抽象基类。应用程序主动抛出的任何错误都应扩展此类 — 它标志着“这是一个已知的、已处理的失败”,而不是意外崩溃。 #### `FraudEvaluationException.java` 当欺诈规则在评估期间意外崩溃时抛出。这是编程或基础设施错误,而不是业务验证失败。 #### `FraudDatabaseException.java` 当数据库操作失败时抛出。将底层错误包装为干净的领域异常。 #### `ClientProfileServiceException.java` 当外部客户资料服务返回错误(例如 HTTP 4xx/5xx)时抛出。标志着下游服务调用失败。 #### `FieldEncryptionException.java` 当加密或解密失败时抛出。通常表示密文损坏或密钥不正确。 #### `GlobalExceptionHandler.java` 捕获应用程序任何地方抛出的每个异常,并将其转换为干净、一致的 `ErrorResponse` JSON 的单一类。如果没有它,未处理的异常将向调用者暴露内部堆栈跟踪。 ### 配置 — “设置” #### `CacheConfig.java` 设置应用程序使用的两个内存缓存: - `clientProfiles` — 缓存客户资料查找 5 分钟,这样就不会在每次交易时都调用外部服务 - `recentTransactionCounts` — 缓存频率计数 2 分钟 #### `EncryptionProperties.java` 保存加密密钥的配置记录。密钥从 `APP_ENCRYPTION_KEY` 环境变量加载,因此永远不会硬编码。 #### `RuleEngineConfig.java` 每条规则具有一个布尔值(`rule001Enabled` 到 `rule006Enabled`)的配置记录。值来自 `application.yml`。将值设置为 `false` 可禁用该规则,而无需重新部署。 #### `OpenApiConfig.java` 配置自动生成 API 文档的 Swagger UI。定义服务标题、版本、描述和联系信息。文档可在 `/swagger-ui/index.html` 访问。 #### `SecurityConfig.java` 配置 Spring Security。定义哪些端点是公开的,哪些需要有效的 JWT。设置 OAuth2 JWT 资源服务器并启用方法级的 `@PreAuthorize` 检查。 ## 技术栈 | 层 | 技术 | |---|---| | 语言 | Java 25 | | 框架 | Spring Boot 3.5.14 | | 构建 | Maven(BOM 管理依赖) | | 数据库(本地) | H2 内存数据库(PostgreSQL 兼容模式) | | 数据库(生产) | PostgreSQL | | Schema 迁移 | Flyway | | 字段加密 | AES-256-GCM (`javax.crypto`) | | 对象映射 | MapStruct 1.6.3 | | 缓存 | Caffeine | | 弹性韧性 | Resilience4j (CircuitBreaker, TimeLimiter, Bulkhead) | | 可观测性 | Micrometer + Prometheus + OpenTelemetry (OTLP) | | 安全性 | Spring Security OAuth2 Resource Server (JWT) | | API 文档 | SpringDoc OpenAPI 2.8.13 | | 代码质量 | Spotless (Palantir Java Format) + Checkstyle | ## 项目结构 ``` src/main/java/za/co/capitecbank/ ├── adapter/ # ClientProfile external service integration │ ├── ClientProfileAdapter.java │ ├── ClientProfileProxyClient.java │ ├── config/ # @ConfigurationProperties + RestClient factory │ ├── impl/ # Resilience4j-decorated implementation │ └── model/ # ClientProfileResponse record ├── config/ # CacheConfig, EncryptionProperties, OpenApiConfig, │ # RuleEngineConfig, SecurityConfig ├── controller/ # FraudController, ServiceController ├── enums/ # AlertSeverity, AlertStatus, Channel, │ # RiskRating, TransactionType ├── exception/ # BusinessException hierarchy + GlobalExceptionHandler ├── fraudrule/ │ ├── FraudRule.java # Strategy interface │ ├── context/ # RuleContext + RuleContextFactory │ ├── impl/ # Six rule implementations │ └── util/ # FraudAlertFactory, TimeWindowCalculator ├── mapper/ # FraudMapper (MapStruct), ClientProfileMapper ├── model/ │ ├── request/ # FraudEvaluationRequest record │ └── response/ # FraudEvaluationResponse, FraudAlertResponse, │ # ErrorResponse records ├── persistence/ │ ├── FraudPersistenceService.java │ ├── converter/ # EncryptedStringConverter (AES-256-GCM) │ ├── entity/ # TransactionEntity, ClientProfileEntity, │ │ # FraudAlertEntity, PpiChangeRecord │ └── repository/ # Spring Data JPA repositories ├── security/ │ ├── FieldEncryptionService.java │ └── impl/AesGcmFieldEncryptionService.java └── service/ ├── FraudEvaluationService.java └── impl/FraudEvaluationServiceImpl.java src/main/resources/ ├── application.yml └── db/migration/ ├── V1__create_transaction_table.sql ├── V2__create_client_profile_table.sql ├── V3__create_fraud_alert_table.sql └── V4__seed_test_client_profiles.sql ``` ## 入门指南 ### 前置条件 - Java 25(推荐使用 Amazon Corretto 25) - Maven 3.9+ 或 `mvnd` - Docker Desktop - PowerShell (Windows) 或 Terminal (Mac/Linux) ### 步骤 1 — 克隆仓库 ``` git clone https://github.com/CP379076/fraud-detection-engine.git cd fraud-detection-engine ``` ### 步骤 2 — 安装 Java 25 从以下地址下载并安装 **Amazon Corretto 25**: ``` https://aws.amazon.com/corretto ``` 安装后,在每次构建会话之前在 PowerShell 中设置 `JAVA_HOME`: ``` $env:JAVA_HOME = "C:\Users\\.jdks\corretto-25.0.3" ``` 验证: ``` java -version ``` ### 步骤 3 — 导入 Zscaler SSL 证书(仅限企业网络) **导出证书:** ``` $tcpClient = New-Object System.Net.Sockets.TcpClient("repo.maven.apache.org", 443) $sslStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream(), $false, {$true}) $sslStream.AuthenticateAsClient("repo.maven.apache.org") $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain $chain.Build($sslStream.RemoteCertificate) $root = $chain.ChainElements[$chain.ChainElements.Count - 1].Certificate [System.IO.File]::WriteAllBytes("C:\Users\$env:USERNAME\corporate-root.cer", $root.Export('Cert')) Write-Host "Exported: $($root.Subject)" ``` **将其导入 JVM 信任库(以管理员身份运行 PowerShell):** ``` $keytool = "C:\Users\$env:USERNAME\.jdks\corretto-25.0.3\bin\keytool.exe" $keystore = "C:\Users\$env:USERNAME\.jdks\corretto-25.0.3\lib\security\cacerts" $certfile = "C:\Users\$env:USERNAME\corporate-root.cer" & $keytool -import -trustcacerts -alias zscaler-root -keystore $keystore -storepass changeit -file $certfile -noprompt ``` 预期输出: ``` Certificate was added to keystore ``` ### 步骤 4 — 构建 JAR ``` mvnd -s settings-personal.xml clean package -DskipTests ``` 或使用标准 Maven: ``` mvn clean package -DskipTests ``` 预期输出: ``` [INFO] BUILD SUCCESS ``` ### 步骤 5 — 启动完整技术栈 ``` docker-compose up --build ``` Docker 按顺序启动三个容器: | 容器 | 端口 | 用途 | |---|---|---| | `fraud-detection-postgres` | `5432` | PostgreSQL 数据库 | | `fraud-detection-keycloak` | `9090` | OAuth2 身份提供者 | | `fraud-detection-engine` | `8080` | 应用程序 | 等待直到您看到: ``` fraud-detection-engine | Started Application in X seconds ``` ### 步骤 6 — 验证技术栈是否已启动 ``` curl.exe http://localhost:8080/actuator/health ``` 预期:`{"status":"UP"}` ``` curl.exe http://localhost:8080/api/v1/health ``` 预期:`fraud-detection-engine is live` ### 步骤 7 — 获取 JWT token ``` $body = "grant_type=client_credentials&client_id=fraud-detection-engine&client_secret=fraud-engine-secret" curl.exe -X POST "http://localhost:9090/realms/fraud-detection-engine/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d $body ``` 从响应中复制 `access_token` 并存储: ``` $token = "" ``` token 将在 1 小时后过期。重新运行上述命令以获取新 token。 ### 步骤 8 — 测试欺诈评估端点 将请求体写入文件(避免 PowerShell 引用问题): ``` '{"account_id":"ACC-001","client_id":"CLIENT-001","amount":500.00,"currency":"ZAR","transaction_type":"DEPOSIT","channel":"ONLINE","timestamp":"2026-06-03T12:00:00"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` ### 停止技术栈 ``` docker-compose down ``` 若要同时清除数据库卷: ``` docker-compose down -v ``` ## API 参考 Base URL: `http://localhost:8080` ### 端点 | 方法 | 路径 | 认证 | 描述 | |---|---|---|---| | `GET` | `/actuator/health` | 无 | Spring 健康检查 | | `GET` | `/api/v1/health` | 无 | 服务存活检查 | | `POST` | `/v1/fraud/evaluations` | Bearer JWT | 评估交易 | ### POST /v1/fraud/evaluations **请求字段:** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `account_id` | String | 是 | | | `client_id` | String | 是 | | | `amount` | Decimal | 是 | 最小值 0.01 | | `currency` | String | 是 | 3 个字符,例如 `ZAR` | | `transaction_type` | Enum | 是 | `DEPOSIT` `WITHDRAWAL` `TRANSFER` `PAYMENT` | | `channel` | Enum | 是 | `ONLINE` `ATM` `BRANCH` `MOBILE` | | `timestamp` | DateTime | 是 | ISO 格式,例如 `2026-06-03T12:00:00` | | `merchant_category` | String | 否 | | | `destination_account_id` | String | 否 | | | `location` | String | 否 | | ### 测试 Payloads 所有 payload 均使用基于文件的方式,以兼容 PowerShell。 #### 无警报 — 正常交易 ``` '{"account_id":"ACC-001","client_id":"CLIENT-001","amount":500.00,"currency":"ZAR","transaction_type":"DEPOSIT","channel":"ONLINE","timestamp":"2026-06-03T12:00:00","location":"Cape Town"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` 预期:`alert_count: 0` #### RULE-002 — 资料变更后大额交易 客户 `CLIENT-LARGE` 的资料今天已更新。任何金额 ≥ 50,000 兰特的转账都会触发此规则。 ``` '{"account_id":"ACC-001","client_id":"CLIENT-LARGE","amount":75000.00,"currency":"ZAR","transaction_type":"TRANSFER","channel":"ONLINE","destination_account_id":"ACC-TARGET-001","timestamp":"2026-06-03T12:00:00","location":"Johannesburg"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` 预期:`alert_count: 1`,`rule_code: RULE-002`,`severity: CRITICAL` #### RULE-003 — 可疑消费行为 客户 `CLIENT-SPEND` 的月平均收入为 10,000 兰特。任何金额 > 30,000 兰特都会触发此规则(收入的 300%)。 ``` '{"account_id":"ACC-001","client_id":"CLIENT-SPEND","amount":35000.00,"currency":"ZAR","transaction_type":"PAYMENT","channel":"MOBILE","timestamp":"2026-06-03T12:00:00","location":"Durban"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` 预期:`alert_count: 1`,`rule_code: RULE-003`,`severity: MEDIUM` #### RULE-005 — 整数金额模式 快速连续发送 3 次相同的整数金额交易以触发该模式。 ``` '{"account_id":"ACC-001","client_id":"CLIENT-001","amount":5000.00,"currency":"ZAR","transaction_type":"WITHDRAWAL","channel":"ATM","timestamp":"2026-06-03T12:00:00"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` 预期:第三次请求返回 `alert_count: 1`,`rule_code: RULE-005`,`severity: MEDIUM` #### RULE-004 — 交易频率激增 在 1 小时内发送 10 笔或以上来自同一客户的交易。 ``` '{"account_id":"ACC-001","client_id":"CLIENT-001","amount":100.00,"currency":"ZAR","transaction_type":"PAYMENT","channel":"ONLINE","timestamp":"2026-06-03T12:00:00"}' | Out-File -FilePath body.json -Encoding utf8NoBOM for ($i = 1; $i -le 11; $i++) { curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" } ``` 预期:在第 10 次请求之后,`alert_count: 1`,`rule_code: RULE-004`,`severity: HIGH` #### 400 Bad Request — 验证失败 ``` '{"account_id":"","client_id":"CLIENT-001","amount":-1,"currency":"ZA","transaction_type":"PAYMENT","channel":"ONLINE","timestamp":"2026-06-03T12:00:00"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d "@body.json" ``` 预期:`400 Bad Request`,附带字段验证错误。 #### 401 Unauthorized — 缺少 token ``` '{"account_id":"ACC-001","client_id":"CLIENT-001","amount":500.00,"currency":"ZAR","transaction_type":"DEPOSIT","channel":"ONLINE","timestamp":"2026-06-03T12:00:00"}' | Out-File -FilePath body.json -Encoding utf8NoBOM curl.exe -X POST "http://localhost:8080/v1/fraud/evaluations" -H "Content-Type: application/json" -d "@body.json" ``` 预期:`401 Unauthorized` **错误响应参考:** | 状态 | 原因 | |---|---| | `400 Bad Request` | 验证失败 — 字段错误列在 `message` 中 | | `401 Unauthorized` | JWT 缺失或无效 | | `403 Forbidden` | JWT 有效但缺少 `fraud:evaluate` scope | | `500 Internal Server Error` | 规则评估失败 | ### 健康检查(无需认证) ``` GET /api/v1/health ``` ### Swagger UI(无需认证) ``` GET /swagger-ui/index.html ``` ## 配置 所有配置均位于 `src/main/resources/application.yml` 中。敏感值通过环境变量进行外部化。 | 环境变量 | 默认值(本地) | 描述 | |---|---|---| | `APP_ENCRYPTION_KEY` | `test-aes-256-key-32byteslong!!!!!` | 用于 PII 字段加密的 32 字节 AES 密钥。**在生产环境中必须被覆盖。** | | `JWT_ISSUER_URI` | `http://localhost:9090/realms/fraud-detection-engine` | 用于 JWT 签名验证的 JWKS 端点 | | `JWT_AUDIENCE` | `fraud-detection-engine` | 传入 JWT 中预期的 `aud` claim | | `H2_CONSOLE_ENABLED` | `false` | 在 `/h2-console` 启用 H2 Web 控制台(仅限本地开发) | | `POSTGRES_PASSWORD` | `frauddetectionengine_local` | PostgreSQL 密码(仅限 Docker) | | `KEYCLOAK_ADMIN_PASSWORD` | `admin` | Keycloak 管理控制台密码(仅限 Docker) | ### 切换欺诈规则 每条规则都可以独立禁用而无需重新部署: ``` app: fraud-rules: rule001-enabled: true # Structuring Over Time rule002-enabled: true # Large Transaction After Profile Change rule003-enabled: true # Suspicious Spend Behaviour rule004-enabled: false # Velocity Spike — disabled rule005-enabled: true # Round Amount Pattern rule006-enabled: true # High-Risk Rapid Movement ``` ### ClientProfile 外部服务 ``` app: http-configs: rest: client-profile-service: url: ${CLIENT_PROFILE_SERVICE_URL:http://localhost:9091} connect-timeout: PT2S read-timeout: PT3S ``` ## 安全性 ### 身份验证 除 `/actuator/health`、`/actuator/info`、`/swagger-ui/**` 和 `/v3/api-docs/**` 之外的所有端点都需要有效的 JWT。 JWT 必须满足: - 由配置的签发者签名(`JWT_ISSUER_URI`) - 包含 `fraud-detection-engine` audience claim - 对于 `POST /v1/fraud/evaluations`,包含 `fraud:evaluate` scope 通过 Docker 运行时,Keycloak 将在 `http://localhost:9090` 自动启动。名为 `fraud-detection-engine` 的 realm 将在启动时从 `keycloak/` 目录导入。 ### PII 字段加密 `ClientProfileEntity.fullName` 和 `ClientProfileEntity.idNumber` 使用 **AES-256-GCM** 进行静态加密: - 使用 `SecureRandom` 为每次加密调用生成随机的 12 字节 IV - IV 作为前缀添加到密文中,以 Base64 格式存储 - GCM 身份验证标签(128 位)可防止密文被篡改 - 密钥来源于 `APP_ENCRYPTION_KEY` 环境变量 ### 密钥 没有任何密钥被提交到版本控制中。有关所需变量,请参见 `.env.example`。 ## 数据库 ### Schema 由 Flyway 管理。迁移将在应用程序启动时自动运行。 | 迁移 | 描述 | |---|---| | `V1` | `transaction` 表 — 存储所有已评估的交易 | | `V2` | `client_profile` 表 + `client_profile_ppi_change` — PII 加密的客户数据 | | `V3` | `fraud_alert` 表 — 包含规则元数据的持久化警报 | | `V4` | 种子数据 — 用于本地开发的测试客户资料 | ### 本地 H2 控制台 当 `H2_CONSOLE_ENABLED=true` 时: ``` URL: http://localhost:8080/h2-console JDBC URL: jdbc:h2:mem:frauddetectionengine Username: sa Password: (leave blank) ``` ### 测试客户资料(由 V4 植入) | `client_id` | 设置 | 触发条件 | |---|---|---| | `CLIENT-LARGE` | 资料已更新,收入 80,000 兰特 | RULE-002,金额 ≥ 50,000 兰特 | | `CLIENT-SPEND` | 月平均收入 10,000 兰特 | RULE-003,金额 > 30,000 兰特 | | `CLIENT-RAPID` | 无特殊资料 | 用于 RULE-006 快速转移测试 | ## 可观测性 ### 指标 在 `GET /actuator/prometheus` 暴露,供 Prometheus 抓取。 | 指标 | 类型 | 标签 | 描述 | |---|---|---|---| | `fraud.alerts.generated` | Counter | `ruleCode` | 每持久化一个警报即递增 | | `fraud.evaluation.duration` | Timer | `clientId` | 完整评估循环持续时间 | | `http.server.requests` | Timer | `uri`, `status` | 标准 Spring HTTP 指标 | ### 链路追踪 通过 Micrometer + OpenTelemetry 实现 W3C `traceparent` 传播。通过以下方式配置 OTLP 端点: ``` management: otlp: tracing: endpoint: ${OTLP_ENDPOINT:http://localhost:4318/v1/traces} ``` ### 健康 ``` GET /actuator/health → {"status": "UP"} GET /actuator/info → build info GET /actuator/metrics → available metric names ``` ## 测试 ``` # 运行所有单元测试(72 个测试) mvn test # 运行集成测试(需要 app context + H2) mvn verify ``` ### 测试覆盖率 | 层 | 测试类 | 测试数 | |---|---|---| | 加密 | `AesGcmFieldEncryptionServiceUnitTest` | 4 | | 字段转换器 | `EncryptedStringConverterUnitTest` | 4 | | 实体 | `TransactionEntityUnitTest`, `ClientProfileEntityUnitTest`, `FraudAlertEntityUnitTest` | 8 | | 持久层 | `FraudPersistenceServiceUnitTest` | 6 | | 规则上下文 | `RuleContextUnitTest`, `RuleContextFactoryUnitTest` | 5 | | 欺诈规则 | `StructuringRule`, `ProfileChangeRule`, `SuspiciousSpendRule`, `VelocityRule`, `RoundAmountRule`, `RapidMovementRule` | 31 | | 引擎 | `FraudEvaluationServiceImplUnitTest` | 5 | | 控制器 | `FraudControllerUnitTest` | 1 | | 异常处理器 | `GlobalExceptionHandlerUnitTest` | 4 | | 适配器 | `ClientProfileAdapterImplUnitTest` | 2 | | 缓存 | `CacheConfigUnitTest` | 2 | | 集成 | `FraudPersistenceIntegrationTest` | 3 |
标签:API集成, CISA项目, Flyway, H2数据库, JS文件枚举, JWT认证, MapStruct, Micrometer, OAuth2, PostgreSQL, REST API, Spring Boot, Web安全, 云计算, 反欺诈, 可观测性, 域名枚举, 实时交易监控, 欺诈检测引擎, 测试用例, 生产就绪, 自定义请求头, 蓝队分析, 规则引擎, 金融交易, 风控系统