添加项目文件。

This commit is contained in:
2026-10-12 16:22:04 +08:00
parent 7c68a0ca0a
commit aad11be43d
1000 changed files with 120807 additions and 0 deletions
@@ -0,0 +1,156 @@
using System.Text;
using Common;
using CommonDomain;
using CommonService;
using Newtonsoft.Json;
namespace AdminHost.Middleware
{
public class ApiLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ApiLoggingMiddleware> _logger;
private readonly IApiLogService _apiLogService;
public ApiLoggingMiddleware(RequestDelegate next, ILogger<ApiLoggingMiddleware> logger, IApiLogService apiLogService)
{
_next = next;
_logger = logger;
_apiLogService = apiLogService;
}
public async Task Invoke(HttpContext httpContext)
{
var request = httpContext.Request;
if (request.Path.StartsWithSegments(new PathString("/api")) && request.Method.ToLower() != "options")
{
var requestTime = DateTime.Now;
var requestBodyContent = string.Empty;
var originalRequest = httpContext.Response.Body;
if (request.Method == "POST")
{
request.EnableBuffering();
requestBodyContent = await new StreamReader(request.Body).ReadToEndAsync();
request.Body.Position = 0;
}
try
{
using (var responseBody = new MemoryStream())
{
var response = httpContext.Response;
response.Body = responseBody;
await _next(httpContext);
string responseBodyContent = null;
responseBodyContent = await FormatResponse(response);
await responseBody.CopyToAsync(originalRequest);
string token = string.Empty, version = string.Empty, userAgent = string.Empty, source = string.Empty, deviceId = string.Empty, device = string.Empty, ip = string.Empty,sign=string.Empty;
if (httpContext.Request != null && httpContext.Request.Headers != null)
{
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Token"]))
{
token = httpContext.Request.Headers["Token"] + ""; }
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Version"]))
{
version = httpContext.Request.Headers["Version"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["User-Agent"]))
{
userAgent = httpContext.Request.Headers["User-Agent"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Source"]))
{
source = httpContext.Request.Headers["Source"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["DeviceId"]))
{
deviceId = httpContext.Request.Headers["DeviceId"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Device"]))
{
device = httpContext.Request.Headers["Device"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Ip"]))
{
ip = httpContext.Request.Headers["Ip"] + "";
}
if (!string.IsNullOrEmpty(httpContext.Request.Headers["Sign"]))
{
sign = httpContext.Request.Headers["Sign"] + "";
}
}
try
{
if (!string.IsNullOrEmpty(responseBodyContent))
{
BaseResponse<object> baseResponse = JsonConvert.DeserializeObject<BaseResponse<object>>(responseBodyContent);
if (baseResponse != null && baseResponse.Data != null)
{
baseResponse.Data = null;
}
responseBodyContent = JsonConvert.SerializeObject(baseResponse);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "API响应日志脱敏序列化失败 path={Path}", request.Path);
}
var now = DateTime.Now;
var apilog = new ApiLog()
{
requestTime = now,
accessToken = token,
clientIP = httpContext.Connection.RemoteIpAddress.ToString(),
consumeTime = (DateTime.Now - requestTime).Milliseconds,
requestHead= JsonConvert.SerializeObject(httpContext.Request.Headers),
requestUrl = request.Path,
requestMethod = request.Method.ToLower(),
requestQuery = request.QueryString.ToString(),
requestBody = requestBodyContent,
httpStatus = httpContext.Response.StatusCode,
responseBody = responseBodyContent,
userAgent = userAgent,
device= device,
deviceId= deviceId,
ip=ip,
source=source,
version=version,
sign=sign
};
await _apiLogService.InsertOneAsync(apilog);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "API日志记录失败 path={Path}", request.Path);
}
finally
{
httpContext.Response.Body = originalRequest;
}
}
else
{
await _next(httpContext);
}
}
private async Task<string> FormatResponse(HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
string text = await new StreamReader(response.Body).ReadToEndAsync();
response.Body.Seek(0, SeekOrigin.Begin);
return text;
}
}
public static class ApiLoggingMiddlewareExtensions
{
public static IApplicationBuilder UseApiLogging(this IApplicationBuilder app)
{
return app.UseMiddleware<ApiLoggingMiddleware>();
}
}
}
@@ -0,0 +1,47 @@
using AdminService.System;
using AdminService.Customer;
using AdminService.Admin;
using Autofac;
using CommonService;
using MongoRepository;
using UserService;
using UserService.BeautifulNumber;
namespace AdminHost.Middleware
{
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(MongoBaseRepository<>)).As(typeof(IMongoBaseRepository<>)).InstancePerLifetimeScope();
builder.RegisterType<RedisService.RedisService>()
.As<RedisService.IRedisService>()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(ApiLogService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(AdminOperationLogService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(SystemService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(UserFeedbackService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterType<CommonService.BackgroundOperationService>()
.As<CommonService.IBackgroundOperationService>()
.InstancePerLifetimeScope();
}
}
}
@@ -0,0 +1,234 @@
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<OperationLogMiddleware> _logger;
public OperationLogMiddleware(RequestDelegate next, ILogger<OperationLogMiddleware> 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<OperationLogMiddleware>();
}
}
}