注入 进行全局的异常日志收集、执行操作日志、参数验证,支持简体中文、繁体中文、粤语、日语、法语、英语.services.ExceptionSetup();// 注入 全局错误日志处 services.ExceptionSetup(ExceptionLog actionOptions);// 注入 全局错误日志处 services.ExceptionSetup(builder.Configuration.GetSection("AopOption:ExceptionLog"));// 注入 全局错误日志处 services.RequestActionSetup();// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(RequestLog actionOptions);// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(builder.Configuration.GetSection("AopOption:RequestLog"));// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.ResourceSetup();//对资源型信息进行过滤 services.ResultSetup();//对结果进行统一 services.ApISafeSetup(AppSign actionOptions);//接口安全校验 services.ApISafeSetup(builder.Configuration.GetSection("AopOption:AppSign"));//接口安全校验 services.ApISignSetup(AppSign actionOptions);//签名验证 ( appKey + signKey + timeStamp + data ); services.ApISignSetup(builder.Configuration.GetSection("AopOption:AppSign"));//签名验证 ( appKey + signKey + timeStamp + data ); services.AddValidateSetup();//模型校验 services.AddUiFilesZipSetup();//将前端UI压缩文件进行解压 不进行接口安全校验 -> NonAplSafeAttribute 不签名验证 -> NonAplSignAttribute 不进行全局的异常日志收集 -> NonExceptionAttribute 不对资源型信息进行过滤 -> NonResourceAttribute 不对结果进行统一 -> NonRestfulResultAttribute
$ dotnet add package RuoVea.ExFilterRuoVea.ExFilter 是一个功能全面的 ASP.NET Core 过滤器组件,提供全局异常处理、请求日志、参数验证、API安全校验等企业级功能。
// 方式一:默认配置
builder.Services.ExceptionSetup();
// 方式二:通过 Action 配置
builder.Services.ExceptionSetup(options =>
{
options.Enabled = true;
options.LogToFile = false;
options.LogMore = false;
});
// 方式三:通过配置文件
builder.Services.ExceptionSetup(builder.Configuration.GetSection("AopOption:ExceptionLog"));
{
"ExceptionLog": {
"Enabled": true,
"LogToFile": false,
"LogMore": false
}
}
// 默认配置
builder.Services.RequestActionSetup();
// 自定义配置
builder.Services.RequestActionSetup(options =>
{
options.Enabled = true;
options.LogToFile = false;
options.LogMore = false;
options.IgnoreApis = "/health,/metrics";
});
// 配置文件方式
builder.Services.RequestActionSetup(builder.Configuration.GetSection("AopOption:RequestLog"));
{
"RequestLog": {
"Enabled": true,
"LogToFile": false,
"LogMore": false,
"IgnoreApis": "/health,/metrics"
}
}
// 对资源型信息进行过滤,常用于防盗链/资源缓存
builder.Services.ResourceSetup();
// 对 API 返回结果进行统一格式化
builder.Services.ResultSetup();
// 接口安全校验
builder.Services.ApISafeSetup(options =>
{
options.AppKeys = "key1,key2,key3";
options.AppKeyName = "appKey";
options.TimeStampName = "timeStamp";
options.ExpiresMinute = 2;
});
// 配置文件方式
builder.Services.ApISafeSetup(builder.Configuration.GetSection("AopOption:ApISafe"));
{
"ApISafe": {
"AppKeys": "key1,key2,key3",
"AppKeyName": "appKey",
"TimeStampName": "timeStamp",
"ExpiresMinute": 2
}
}
// 签名验证 MD5(appKey + signKey + timeStamp + data)
builder.Services.ApISignSetup(options =>
{
options.AppKeys = "key1,key2,key3";
options.AppKeyName = "appKey";
options.TimeStampName = "timeStamp";
options.ExpiresMinute = 2;
options.SignKey = "your-sign-key";
options.SignatureName = "signature";
options.IgnoreApi = "/public/*,/health";
});
// 配置文件方式
builder.Services.ApISignSetup(builder.Configuration.GetSection("AopOption:AppSign"));{
"AppSign": {
"AppKeys": "key1,key2,key3",
"AppKeyName": "appKey",
"TimeStampName": "timeStamp",
"ExpiresMinute": 2,
"SignKey": "your-sign-key",
"SignatureName": "signature",
"IgnoreApi": "/public/*,/health"
}
}// 将前端 UI 压缩文件进行解压
builder.Services.AddUiFilesZipSetup();
// 使用虚拟路径中间件
app.UseVirtualPathMiddle();{
"VirtualPath": "/myapp"
}public interface IRestfulFilterLog
{
// 成功返回值处理
IActionResult OnSucceeded(ActionExecutedContext context, object data);
// 验证失败返回值处理
IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata);
// 异常日志记录
void ExceptionLog(ExceptionVo exception);
// 操作日志记录
void OperationLog(OperationVo operation);
}public class RestfulFilterLog : IRestfulFilterLog
{
// 操作日志记录(可重写)
public virtual void OperationLog(OperationVo operation)
{
// 默认实现
}
// 异常日志记录(可重写)
public virtual void ExceptionLog(ExceptionVo exception)
{
// 默认实现
}
}public class ExceptionVo
{
public string RequestUrl { get; set; }
public string RequestMethod { get; set; }
public string UserAgent { get; set; }
public string IPAddress { get; set; }
public DateTime OccurredTime { get; set; }
public string ExceptionType { get; set; }
public string ExceptionMessage { get; set; }
public string StackTrace { get; set; }
public string InnerException { get; set; }
}public class OperationVo
{
public string RequestUrl { get; set; }
public string RequestMethod { get; set; }
public string UserAgent { get; set; }
public string IPAddress { get; set; }
public DateTime RequestTime { get; set; }
public long ExecutionTime { get; set; }
public string Parameters { get; set; }
public string Response { get; set; }
public int StatusCode { get; set; }
public string UserId { get; set; }
public string UserName { get; set; }
}public class CustomRestfulFilterLog : RestfulFilterLog
{
private readonly ILogger<CustomRestfulFilterLog> _logger;
private readonly IOperationLogService _operationLogService;
public CustomRestfulFilterLog(ILogger<CustomRestfulFilterLog> logger,
IOperationLogService operationLogService)
{
_logger = logger;
_operationLogService = operationLogService;
}
// 重写操作日志记录方法
public override void OperationLog(OperationVo operation)
{
// 记录到日志系统
_logger.LogInformation("操作日志: {Url} {Method} {StatusCode} {ExecutionTime}ms",
operation.RequestUrl, operation.RequestMethod, operation.StatusCode, operation.ExecutionTime);
// 保存到数据库
_operationLogService.SaveAsync(new OperationLogEntity
{
Url = operation.RequestUrl,
Method = operation.RequestMethod,
UserId = operation.UserId,
UserName = operation.UserName,
IpAddress = operation.IPAddress,
UserAgent = operation.UserAgent,
Parameters = operation.Parameters,
Response = operation.Response,
StatusCode = operation.StatusCode,
ExecutionTime = operation.ExecutionTime,
RequestTime = operation.RequestTime
});
}
// 重写异常日志记录方法
public override void ExceptionLog(ExceptionVo exception)
{
// 记录异常到日志系统
_logger.LogError(exception.Exception,
"异常信息: {Url} {Method} {ExceptionType}",
exception.RequestUrl, exception.RequestMethod, exception.ExceptionType);
// 发送异常通知
SendExceptionNotification(exception);
}
private void SendExceptionNotification(ExceptionVo exception)
{
// 发送邮件、短信、钉钉等通知
// 实现异常告警逻辑
}
}// 注册自定义的过滤器日志处理器
builder.Services.AddRestfulSetup<CustomRestfulFilterLog>();[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
[HttpGet("profile")]
public IActionResult GetUserProfile()
{
// 自动记录操作日志和异常
var user = new { Id = 1, Name = "张三", Email = "zhangsan@example.com" };
return Ok(user);
}
[HttpPost("update")]
[NonAplSign] // 不进行签名验证
public IActionResult UpdateUser([FromBody] UserUpdateDto dto)
{
// 自动参数验证
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// 业务逻辑...
return Ok(new { Success = true, Message = "更新成功" });
}
[HttpGet("sensitive-data")]
[NonResource] // 不对资源进行过滤
public IActionResult GetSensitiveData()
{
// 返回敏感数据,不进行资源过滤
return Ok(new { Data = "敏感信息" });
}
[HttpPost("batch-operation")]
[NonException] // 不进行异常日志收集
public IActionResult BatchOperation()
{
// 批量操作,不记录异常日志
try
{
// 业务逻辑...
return Ok();
}
catch
{
// 异常不会被全局异常过滤器捕获
return StatusCode(500);
}
}
}// 前端签名生成示例
function generateSignature(appKey, signKey, data) {
const timeStamp = Math.floor(Date.now() / 1000) + 1000; // 当前时间戳+1000秒
const signContent = appKey + signKey + timeStamp + JSON.stringify(data);
return md5(signContent); // 使用 MD5 加密
}
// 请求头设置
const headers = {
'appKey': 'your-app-key',
'timeStamp': timeStamp,
'signature': generateSignature('your-app-key', 'your-sign-key', requestData)
};public class SignatureService
{
public bool VerifySignature(string appKey, string timeStamp, string data, string signature, string signKey)
{
// 验证时间戳有效期
if (!IsTimestampValid(timeStamp, 2)) // 2分钟有效期
{
return false;
}
// 验证 appKey 有效性
if (!IsAppKeyValid(appKey))
{
return false;
}
// 生成期望的签名
string expectedSignature = GenerateMD5(appKey + signKey + timeStamp + data);
// 比较签名
return signature == expectedSignature;
}
private bool IsTimestampValid(string timestamp, int expiresMinute)
{
if (!long.TryParse(timestamp, out long ts))
return false;
var requestTime = DateTimeOffset.FromUnixTimeSeconds(ts).DateTime;
var now = DateTime.Now;
return now <= requestTime && requestTime <= now.AddMinutes(expiresMinute);
}
private bool IsAppKeyValid(string appKey)
{
var validAppKeys = new[] { "key1", "key2", "key3" };
return validAppKeys.Contains(appKey);
}
private string GenerateMD5(string input)
{
using var md5 = MD5.Create();
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}public class RequestInfoService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public RequestInfoService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public RequestInfo GetRequestInfo()
{
var context = _httpContextAccessor.HttpContext;
return new RequestInfo
{
Url = context.Request.GetRequestUrlAddress(),
Host = context.Request.GetRequestHost(),
Browser = context.GetBrowser(),
OS = context.GetOSVersion(),
IP = context.GetIp(),
UserAgent = context.UserAgent(),
ClientInfo = context.GetDefault()
};
}
public void SigninToSwagger(string token)
{
_httpContextAccessor.HttpContext.SigninToSwagger(token);
}
public void SignoutFromSwagger()
{
_httpContextAccessor.HttpContext.SignoutToSwagger();
}
}
public class RequestInfo
{
public string Url { get; set; }
public string Host { get; set; }
public string Browser { get; set; }
public string OS { get; set; }
public string IP { get; set; }
public string UserAgent { get; set; }
public ClientInfo ClientInfo { get; set; }
}var builder = WebApplication.CreateBuilder(args);
// 添加控制器
builder.Services.AddControllers();
// 配置过滤器
builder.Services.ExceptionSetup(builder.Configuration.GetSection("AopOption:ExceptionLog"));
builder.Services.RequestActionSetup(builder.Configuration.GetSection("AopOption:RequestLog"));
builder.Services.ResourceSetup();
builder.Services.ResultSetup();
builder.Services.ApISafeSetup(builder.Configuration.GetSection("AopOption:ApISafe"));
builder.Services.ApISignSetup(builder.Configuration.GetSection("AopOption:AppSign"));
// 注册自定义过滤器日志
builder.Services.AddRestfulSetup<CustomRestfulFilterLog>();
// 规范化模型验证
builder.Services.AddRestfulModelsSetup(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
// 前端 UI 文件处理
builder.Services.AddUiFilesZipSetup();
var app = builder.Build();
// 使用虚拟路径中间件
app.UseVirtualPathMiddle();
// 其他中间件...
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();{
"AopOption": {
"RequestLog": {
"Enabled": true,
"LogToFile": false,
"LogMore": true,
"IgnoreApis": "/health,/metrics,/swagger"
},
"ExceptionLog": {
"Enabled": true,
"LogToFile": true,
"LogMore": true
},
"ApISafe": {
"AppKeys": "web-app,mobile-app,admin-app",
"AppKeyName": "appKey",
"TimeStampName": "timeStamp",
"ExpiresMinute": 2
},
"AppSign": {
"AppKeys": "web-app,mobile-app,admin-app",
"AppKeyName": "appKey",
"TimeStampName": "timeStamp",
"ExpiresMinute": 2,
"SignKey": "your-secret-sign-key-2024",
"SignatureName": "signature",
"IgnoreApi": "/public/*,/health,/swagger"
}
},
"VirtualPath": "/myapp"
}[NonAplSafe] - 不进行接口安全校验[NonAplSign] - 不进行签名验证[NonException] - 不进行全局异常日志收集[NonResource] - 不对资源型信息进行过滤[NonRestfulResult] - 不对结果进行统一这个过滤器组件为 ASP.NET Core 应用提供了企业级的全局处理能力,大幅提升了应用的稳定性、安全性和可维护性。