feat: add audit domain model, repository interface, AuditService, and unit test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
package com.cameleer3.server.core.admin;
|
||||
|
||||
public enum AuditCategory {
|
||||
INFRA, AUTH, USER_MGMT, CONFIG
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.cameleer3.server.core.admin;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
|
||||
public record AuditRecord(
|
||||
long id,
|
||||
Instant timestamp,
|
||||
String username,
|
||||
String action,
|
||||
AuditCategory category,
|
||||
String target,
|
||||
Map<String, Object> detail,
|
||||
AuditResult result,
|
||||
String ipAddress,
|
||||
String userAgent
|
||||
) {
|
||||
/** Factory for creating new records (id and timestamp assigned by DB) */
|
||||
public static AuditRecord create(String username, String action, AuditCategory category,
|
||||
String target, Map<String, Object> detail, AuditResult result,
|
||||
String ipAddress, String userAgent) {
|
||||
return new AuditRecord(0, null, username, action, category, target, detail, result, ipAddress, userAgent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.cameleer3.server.core.admin;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
public interface AuditRepository {
|
||||
|
||||
void insert(AuditRecord record);
|
||||
|
||||
record AuditQuery(
|
||||
String username,
|
||||
AuditCategory category,
|
||||
String search,
|
||||
Instant from,
|
||||
Instant to,
|
||||
String sort,
|
||||
String order,
|
||||
int page,
|
||||
int size
|
||||
) {}
|
||||
|
||||
record AuditPage(List<AuditRecord> items, long totalCount) {}
|
||||
|
||||
AuditPage find(AuditQuery query);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.cameleer3.server.core.admin;
|
||||
|
||||
public enum AuditResult {
|
||||
SUCCESS, FAILURE
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.cameleer3.server.core.admin;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AuditService {
|
||||
private static final Logger log = LoggerFactory.getLogger(AuditService.class);
|
||||
private final AuditRepository repository;
|
||||
|
||||
public AuditService(AuditRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/** Log an action using the current SecurityContext for username */
|
||||
public void log(String action, AuditCategory category, String target,
|
||||
Map<String, Object> detail, AuditResult result,
|
||||
HttpServletRequest request) {
|
||||
String username = extractUsername();
|
||||
log(username, action, category, target, detail, result, request);
|
||||
}
|
||||
|
||||
/** Log an action with explicit username (for pre-auth contexts like login) */
|
||||
public void log(String username, String action, AuditCategory category, String target,
|
||||
Map<String, Object> detail, AuditResult result,
|
||||
HttpServletRequest request) {
|
||||
String ip = request != null ? request.getRemoteAddr() : null;
|
||||
String userAgent = request != null ? request.getHeader("User-Agent") : null;
|
||||
AuditRecord record = AuditRecord.create(username, action, category, target, detail, result, ip, userAgent);
|
||||
|
||||
repository.insert(record);
|
||||
|
||||
log.info("AUDIT: user={} action={} category={} target={} result={}",
|
||||
username, action, category, target, result);
|
||||
}
|
||||
|
||||
private String extractUsername() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth != null && auth.getName() != null) {
|
||||
String name = auth.getName();
|
||||
return name.startsWith("user:") ? name.substring(5) : name;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user