72 lines
2.6 KiB
C#
72 lines
2.6 KiB
C#
using MiaoJiZhang.Domain.Entities;
|
|
using MiaoJiZhang.Infrastructure.Persistence;
|
|
|
|
namespace MiaoJiZhang.Api.Services;
|
|
|
|
public sealed class AdminAuditMiddleware(RequestDelegate next)
|
|
{
|
|
public async Task InvokeAsync(HttpContext context, AppDbContext db)
|
|
{
|
|
var isAdmin = context.Request.Path.StartsWithSegments("/api/admin");
|
|
var isAuth = context.Request.Path.StartsWithSegments("/api/admin/auth");
|
|
var shouldAudit = isAdmin && (isAuth ||
|
|
!AdminSessionService.IsSafeMethod(context.Request.Method));
|
|
if (!shouldAudit)
|
|
{
|
|
await next(context);
|
|
return;
|
|
}
|
|
|
|
Exception? failure = null;
|
|
try
|
|
{
|
|
await next(context);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
failure = exception;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
var principal = AdminRequestContext.Principal(context);
|
|
var attemptedUsername = context.Items.TryGetValue(
|
|
AdminRequestContext.AuditUsernameKey,
|
|
out var attemptedValue)
|
|
? attemptedValue?.ToString()
|
|
: null;
|
|
var status = failure is null
|
|
? context.Response.StatusCode
|
|
: StatusCodes.Status500InternalServerError;
|
|
db.AdminAuditLogs.Add(new AdminAuditLog
|
|
{
|
|
AdminUserId = principal?.UserId,
|
|
Username = principal?.Username ?? attemptedUsername,
|
|
Action = ActionName(context),
|
|
Resource = context.Request.Path.Value ?? "/api/admin",
|
|
HttpMethod = context.Request.Method,
|
|
Path = (context.Request.Path + context.Request.QueryString).ToString(),
|
|
StatusCode = status,
|
|
Success = failure is null && status < 400,
|
|
Detail = failure?.GetType().Name,
|
|
IpAddress = context.Connection.RemoteIpAddress?.ToString(),
|
|
CreatedAt = DateTime.UtcNow,
|
|
});
|
|
await db.SaveChangesAsync(CancellationToken.None);
|
|
}
|
|
catch
|
|
{
|
|
// Audit persistence must not replace the original API result.
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string ActionName(HttpContext context)
|
|
{
|
|
var path = context.Request.Path.Value?.Trim('/').Replace('/', '.') ?? "api.admin";
|
|
return $"{context.Request.Method.ToLowerInvariant()}.{path}";
|
|
}
|
|
}
|