116 lines
3.7 KiB
C#
116 lines
3.7 KiB
C#
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using line_gestao_api.Data;
|
|
using line_gestao_api.Models;
|
|
|
|
namespace line_gestao_api.Services;
|
|
|
|
public class SystemAuditService : ISystemAuditService
|
|
{
|
|
private const int ActionMaxLength = 20;
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
};
|
|
|
|
private readonly AppDbContext _db;
|
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
private readonly ITenantProvider _tenantProvider;
|
|
|
|
public SystemAuditService(
|
|
AppDbContext db,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
ITenantProvider tenantProvider)
|
|
{
|
|
_db = db;
|
|
_httpContextAccessor = httpContextAccessor;
|
|
_tenantProvider = tenantProvider;
|
|
}
|
|
|
|
public async Task LogAsync(string action, Guid targetTenantId, object? metadata = null, CancellationToken cancellationToken = default)
|
|
{
|
|
var actorTenantId = _tenantProvider.ActorTenantId;
|
|
if (!actorTenantId.HasValue || actorTenantId.Value == Guid.Empty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var user = _httpContextAccessor.HttpContext?.User;
|
|
var userId = ResolveUserId(user);
|
|
var userName = ResolveUserName(user);
|
|
var userEmail = ResolveUserEmail(user);
|
|
|
|
var request = _httpContextAccessor.HttpContext?.Request;
|
|
var requestPath = request?.Path.Value;
|
|
var requestMethod = request?.Method;
|
|
var ipAddress = _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
|
|
var safeMetadataJson = JsonSerializer.Serialize(metadata ?? new { }, JsonOptions);
|
|
var normalizedAction = NormalizeAction(action);
|
|
|
|
_db.AuditLogs.Add(new AuditLog
|
|
{
|
|
TenantId = actorTenantId.Value,
|
|
ActorUserId = userId,
|
|
ActorTenantId = actorTenantId.Value,
|
|
TargetTenantId = targetTenantId,
|
|
OccurredAtUtc = DateTime.UtcNow,
|
|
Action = normalizedAction,
|
|
Page = "System",
|
|
EntityName = "System",
|
|
EntityId = targetTenantId.ToString(),
|
|
EntityLabel = null,
|
|
ChangesJson = "[]",
|
|
MetadataJson = safeMetadataJson,
|
|
UserId = userId,
|
|
UserName = userName,
|
|
UserEmail = userEmail,
|
|
RequestPath = requestPath,
|
|
RequestMethod = requestMethod,
|
|
IpAddress = ipAddress
|
|
});
|
|
|
|
await _db.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
private static string NormalizeAction(string? action)
|
|
{
|
|
var normalized = (action ?? string.Empty).Trim().ToUpperInvariant();
|
|
if (string.IsNullOrEmpty(normalized))
|
|
{
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
if (normalized.Length <= ActionMaxLength)
|
|
{
|
|
return normalized;
|
|
}
|
|
|
|
return normalized[..ActionMaxLength];
|
|
}
|
|
|
|
private static Guid? ResolveUserId(ClaimsPrincipal? user)
|
|
{
|
|
var raw = user?.FindFirstValue(ClaimTypes.NameIdentifier)
|
|
?? user?.FindFirstValue(JwtRegisteredClaimNames.Sub)
|
|
?? user?.FindFirstValue("sub");
|
|
|
|
return Guid.TryParse(raw, out var parsed) ? parsed : null;
|
|
}
|
|
|
|
private static string? ResolveUserName(ClaimsPrincipal? user)
|
|
{
|
|
return user?.FindFirstValue("name")
|
|
?? user?.FindFirstValue(ClaimTypes.Name)
|
|
?? user?.Identity?.Name;
|
|
}
|
|
|
|
private static string? ResolveUserEmail(ClaimsPrincipal? user)
|
|
{
|
|
return user?.FindFirstValue(ClaimTypes.Email)
|
|
?? user?.FindFirstValue(JwtRegisteredClaimNames.Email)
|
|
?? user?.FindFirstValue("email");
|
|
}
|
|
}
|