using System.Text; using Domain.Admin.Admin; using Domain.Admin.Admin.ENum; namespace AdminHost.Middleware { public class OperationLogMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public OperationLogMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context, Domain.Admin.Admin.IAdminOperationLogService logService) { var path = context.Request.Path.Value ?? ""; var method = context.Request.Method; bool shouldLog = path.StartsWith("/adminapi", StringComparison.OrdinalIgnoreCase) || path.StartsWith("/api/Admin", StringComparison.OrdinalIgnoreCase); if (!shouldLog) { await _next(context); return; } if (path.Contains("/login", StringComparison.OrdinalIgnoreCase) || path.Contains("/GetAccessToken", StringComparison.OrdinalIgnoreCase)) { await _next(context); return; } string? requestBody = null; if (method == "POST" || method == "PUT") { context.Request.EnableBuffering(); using var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true); requestBody = await reader.ReadToEndAsync(); context.Request.Body.Position = 0; } var startTime = DateTime.Now; string? ip = GetClientIp(context); string? adminId = null; string? adminName = null; if (context.User.Identity?.IsAuthenticated == true) { adminId = context.User.FindFirst("uid")?.Value; adminName = context.User.FindFirst("dname")?.Value ?? context.User.FindFirst(System.Security.Claims.ClaimTypes.Name)?.Value; } if (adminId == "administrator" || adminName == "administrator") { await _next(context); return; } int statusCode = 200; try { await _next(context); statusCode = context.Response.StatusCode; } catch (Exception ex) { statusCode = 500; _logger.LogError(ex, "请求处理异常"); throw; } _ = Task.Run(async () => { try { var log = new AdminOperationLog { AdminId = adminId, AdminName = adminName, Module = (int)GetModuleFromPath(path), ActionType = GetActionType(method, path), Description = $"{GetActionType(method, path)} - {path}", HttpMethod = method, RequestPath = path, RequestParams = requestBody?.Length > 4000 ? requestBody[..4000] : requestBody, Response = null, Ip = ip, Status = statusCode >= 200 && statusCode < 400 ? 1 : 0, OperateTime = startTime }; await logService.AddLog(log); } catch (Exception ex) { _logger.LogError(ex, "记录操作日志失败"); } }); } private static string? GetClientIp(HttpContext context) { var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (string.IsNullOrEmpty(ip)) { ip = context.Connection.RemoteIpAddress?.ToString(); } return ip; } private static EnumOperationModule GetModuleFromPath(string path) { if (path.Contains("/AdminUser", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.User; if (path.Contains("/Customer", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Customer; if (path.Contains("/BeautifulNumber", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.BeautifulNumber; if (path.Contains("/Notice", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Notice; if (path.Contains("/Task", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Task; if (path.Contains("/GameConfig", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.GameConfig; if (path.Contains("/Room", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Room; if (path.Contains("/System/user", StringComparison.OrdinalIgnoreCase) || path.Contains("/system/user", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.SystemUser; if (path.Contains("/System/role", StringComparison.OrdinalIgnoreCase) || path.Contains("/system/role", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Role; if (path.Contains("/System/nav", StringComparison.OrdinalIgnoreCase) || path.Contains("/system/nav", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Navigation; if (path.Contains("/System/dic", StringComparison.OrdinalIgnoreCase) || path.Contains("/system/dic", StringComparison.OrdinalIgnoreCase)) return EnumOperationModule.Dictionary; return EnumOperationModule.Other; } private static string GetActionType(string method, string path) { if (path.Contains("/Ban", StringComparison.OrdinalIgnoreCase) || path.Contains("/ban", StringComparison.OrdinalIgnoreCase)) return "封号"; if (path.Contains("/Unban", StringComparison.OrdinalIgnoreCase) || path.Contains("/unban", StringComparison.OrdinalIgnoreCase)) return "解封"; if (path.Contains("/Batch", StringComparison.OrdinalIgnoreCase) || path.Contains("/batch", StringComparison.OrdinalIgnoreCase)) return "批量操作"; if (path.Contains("/Email", StringComparison.OrdinalIgnoreCase) || path.Contains("/email", StringComparison.OrdinalIgnoreCase)) return "发送邮件"; if (path.Contains("/Init", StringComparison.OrdinalIgnoreCase) || path.Contains("/init", StringComparison.OrdinalIgnoreCase)) return "初始化"; if (path.Contains("/Freeze", StringComparison.OrdinalIgnoreCase) || path.Contains("/freeze", StringComparison.OrdinalIgnoreCase)) return "冻结"; if (path.Contains("/Unfreeze", StringComparison.OrdinalIgnoreCase) || path.Contains("/unfreeze", StringComparison.OrdinalIgnoreCase)) return "解冻"; if (path.Contains("/Give", StringComparison.OrdinalIgnoreCase) || path.Contains("/give", StringComparison.OrdinalIgnoreCase)) return "赠送"; if (path.Contains("/Clear", StringComparison.OrdinalIgnoreCase) || path.Contains("/clear", StringComparison.OrdinalIgnoreCase)) return "清空"; if (path.Contains("/Robot", StringComparison.OrdinalIgnoreCase) || path.Contains("/robot", StringComparison.OrdinalIgnoreCase)) return "机器人管理"; if (path.Contains("/state", StringComparison.OrdinalIgnoreCase) || path.Contains("/State", StringComparison.OrdinalIgnoreCase)) return "设置状态"; if (path.Contains("/icon", StringComparison.OrdinalIgnoreCase) || path.Contains("/Icon", StringComparison.OrdinalIgnoreCase)) return "修改头像"; if (path.Contains("/list", StringComparison.OrdinalIgnoreCase) || path.Contains("/List", StringComparison.OrdinalIgnoreCase) || path.Contains("/GetAll", StringComparison.OrdinalIgnoreCase) || path.Contains("/getall", StringComparison.OrdinalIgnoreCase) || path.Contains("/Get", StringComparison.OrdinalIgnoreCase) || path.Contains("/get", StringComparison.OrdinalIgnoreCase) || path.Contains("/check", StringComparison.OrdinalIgnoreCase) || path.Contains("/Check", StringComparison.OrdinalIgnoreCase)) return "查询"; if (path.Contains("/add", StringComparison.OrdinalIgnoreCase) || path.Contains("/create", StringComparison.OrdinalIgnoreCase) || path.Contains("/Add", StringComparison.OrdinalIgnoreCase) || path.Contains("/Create", StringComparison.OrdinalIgnoreCase) || path.Contains("/send", StringComparison.OrdinalIgnoreCase) || path.Contains("/Send", StringComparison.OrdinalIgnoreCase)) return "新增"; if (path.Contains("/update", StringComparison.OrdinalIgnoreCase) || path.Contains("/edit", StringComparison.OrdinalIgnoreCase) || path.Contains("/Update", StringComparison.OrdinalIgnoreCase) || path.Contains("/Edit", StringComparison.OrdinalIgnoreCase) || path.Contains("/set-", StringComparison.OrdinalIgnoreCase)) return "修改"; if (path.Contains("/delete", StringComparison.OrdinalIgnoreCase) || path.Contains("/Delete", StringComparison.OrdinalIgnoreCase)) return "删除"; return method switch { "GET" => "查询", "POST" => "新增", "PUT" => "修改", "DELETE" => "删除", _ => "操作" }; } } public static class OperationLogMiddlewareExtensions { public static IApplicationBuilder UseOperationLog(this IApplicationBuilder builder) { return builder.UseMiddleware(); } } }