package com.baiyue.audit.controller; import com.baiyue.audit.dto.AuditIngestRequest; import com.baiyue.audit.service.AuditIngestService; import com.baiyue.common.core.api.ApiResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; /** * 内部审计事件接收接口,校验服务间提交的审计数据并交由审计服务持久化。 */ @Tag( name = "Internal audit ingestion / 内部审计写入", description = "Internal service-to-service API for immutable business audit events. / 服务间写入不可变业务审计事件的内部接口。" ) @RestController @RequestMapping("/internal/audit/events") public class AuditIngestController { private static final String INTERNAL_SERVICE_TOKEN_HEADER = "X-Internal-Service-Token"; @Resource private AuditIngestService service; @Value("${baiyue.security.internal-service-token:}") private String internalServiceToken; @Operation( summary = "Ingest business audit event / 写入业务审计事件", description = "Validates and stores one sanitized event in baiyue_audit.sys_audit_log. / 校验并将一条脱敏事件写入 baiyue_audit.sys_audit_log。" ) @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "202", description = "Event accepted and stored / 事件已接收并存储"), }) @PostMapping public ResponseEntity> ingest( @RequestHeader(value = INTERNAL_SERVICE_TOKEN_HEADER, required = false) String providedToken, @Valid @RequestBody AuditIngestRequest event) { if (!tokenMatches(providedToken)) { return ResponseEntity.status(HttpStatus.FORBIDDEN) .body(ApiResponse.failure(com.baiyue.common.core.api.ResultCode.FORBIDDEN, "Internal service token is invalid", null, null)); } service.ingest(event); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ApiResponse.success(null)); } private boolean tokenMatches(String providedToken) { if (providedToken == null || providedToken.isBlank() || internalServiceToken == null || internalServiceToken.isBlank()) { return false; } return MessageDigest.isEqual( internalServiceToken.getBytes(StandardCharsets.UTF_8), providedToken.getBytes(StandardCharsets.UTF_8)); } }