操作日志功能完善
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using IPTools.Core;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
@@ -6,36 +8,92 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Yi.Framework.Common.Helper;
|
||||
using Yi.Framework.Common.Models;
|
||||
using Yi.Framework.Interface;
|
||||
using Yi.Framework.Model.Models;
|
||||
|
||||
namespace Yi.Framework.WebCore.AttributeExtend
|
||||
{
|
||||
public class GlobalLogAttribute : ActionFilterAttribute
|
||||
{
|
||||
private ILogger<GlobalLogAttribute> _logger;
|
||||
private IOperationLogService _operationLogService;
|
||||
//注入一个日志服务
|
||||
public GlobalLogAttribute(ILogger<GlobalLogAttribute> logger)
|
||||
public GlobalLogAttribute(ILogger<GlobalLogAttribute> logger, IOperationLogService operationLogService)
|
||||
{
|
||||
_logger = logger;
|
||||
_operationLogService = operationLogService;
|
||||
}
|
||||
|
||||
public override void OnResultExecuted(ResultExecutedContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
//查找标签,获取标签对象
|
||||
//判断标签是在方法上
|
||||
if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return;
|
||||
|
||||
//查找标签,获取标签对象
|
||||
LogAttribute logAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
|
||||
.FirstOrDefault(a => a.GetType().Equals(typeof(LogAttribute))) as LogAttribute;
|
||||
if (logAttribute == null) return;
|
||||
|
||||
string controller = context.RouteData.Values["Controller"].ToString();
|
||||
string action = context.RouteData.Values["Action"].ToString();
|
||||
string ip = "127.0.0.1";
|
||||
string ipData = "深圳";
|
||||
//空对象直接返回
|
||||
if (logAttribute is null) return;
|
||||
|
||||
////获取控制器名
|
||||
//string controller = context.RouteData.Values["Controller"].ToString();
|
||||
|
||||
////获取方法名
|
||||
//string action = context.RouteData.Values["Action"].ToString();
|
||||
|
||||
//获取Ip
|
||||
string ip = context.HttpContext.GetClientIp();
|
||||
|
||||
//根据ip获取地址
|
||||
|
||||
//var ipTool = IpTool.Search(ip);
|
||||
//string location = ipTool.Province + " " + ipTool.City;
|
||||
|
||||
//日志服务插入一条操作记录即可
|
||||
|
||||
var logEntity = new OperationLogEntity();
|
||||
|
||||
logEntity.OperIp = ip;
|
||||
//logEntity.OperLocation = location;
|
||||
logEntity.OperType = logAttribute.OperType.GetHashCode();
|
||||
logEntity.Title = logAttribute.Title;
|
||||
logEntity.RequestMethod = context.HttpContext.Request.Method;
|
||||
logEntity.Method = context.HttpContext.Request.Path.Value;
|
||||
logEntity.IsDeleted = false;
|
||||
logEntity.OperUser= context.HttpContext.GetUserNameInfo();
|
||||
if (logAttribute.IsSaveResponseData)
|
||||
{
|
||||
if (context.Result is ContentResult result && result.ContentType == "application/json")
|
||||
{
|
||||
logEntity.RequestResult = result.Content.Replace("\r\n", "").Trim();
|
||||
}
|
||||
if (context.Result is JsonResult result2)
|
||||
{
|
||||
logEntity.RequestResult = result2.Value?.ToString();
|
||||
}
|
||||
|
||||
if (context.Result is ObjectResult result3)
|
||||
{
|
||||
logEntity.RequestResult = JsonHelper.ObjToStr(result3.Value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (logAttribute.IsSaveRequestData)
|
||||
{
|
||||
logEntity.RequestParam = context.HttpContext.GetRequestValue(logEntity.RequestMethod);
|
||||
}
|
||||
|
||||
_operationLogService._repository.InsertReturnSnowflakeId(logEntity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"操作日志错误:{ex.Message}");
|
||||
_logger.LogError(ex, $"操作日志记录错误:{ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,30 @@ namespace Yi.Framework.WebCore.AttributeExtend
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class LogAttribute : Attribute
|
||||
{
|
||||
private OperationEnum OperationType { get; set; }
|
||||
/// <summary>
|
||||
/// 操作类型
|
||||
/// </summary>
|
||||
public OperEnum OperType { get; set; }
|
||||
|
||||
public LogAttribute(OperationEnum operationType)
|
||||
/// <summary>
|
||||
/// 日志标题(模块)
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否保存请求数据
|
||||
/// </summary>
|
||||
public bool IsSaveRequestData { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否保存返回数据
|
||||
/// </summary>
|
||||
public bool IsSaveResponseData { get; set; } = true;
|
||||
|
||||
public LogAttribute(string title, OperEnum operationType)
|
||||
{
|
||||
this.OperationType = operationType;
|
||||
this.Title = title;
|
||||
this.OperType = operationType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,12 @@ internal class JsonOptionsWritable<TOptions> : FileOptionsWritableBase<TOptions>
|
||||
|
||||
public override void Update(Action<TOptions> configuration)
|
||||
{
|
||||
JObject? jObject = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(this.FileName));
|
||||
JObject jObject = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(this.FileName));
|
||||
if (jObject != null)
|
||||
{
|
||||
TOptions option = this.Monitor.CurrentValue ?? new TOptions();
|
||||
|
||||
if (jObject.TryGetValue(this.Section, out JToken? jtoken))
|
||||
if (jObject.TryGetValue(this.Section, out JToken jtoken))
|
||||
{
|
||||
option = JsonConvert.DeserializeObject<TOptions>(jtoken.ToString()) ?? new TOptions();
|
||||
configuration?.Invoke(option);
|
||||
|
||||
@@ -10,10 +10,11 @@ using System.Threading.Tasks;
|
||||
using Yi.Framework.Model.Models;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Yi.Framework.WebCore
|
||||
{
|
||||
public static class CommonExtend
|
||||
public static class HttpContextExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否为异步请求
|
||||
@@ -45,7 +46,7 @@ namespace Yi.Framework.WebCore
|
||||
public static string GetUserNameInfo(this HttpContext httpContext)
|
||||
{
|
||||
var p = httpContext;
|
||||
return httpContext.User.Claims.FirstOrDefault(u => u.Type == JwtRegisteredClaimNames.Name).Value;
|
||||
return httpContext.User.Claims.FirstOrDefault(u => u.Type == "userName")?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,6 +70,8 @@ namespace Yi.Framework.WebCore
|
||||
var p = httpContext;
|
||||
return httpContext.User.Claims.FirstOrDefault(u => u.Type == "permission").Value;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 基于HttpContext,当前鉴权方式解析,获取用户信息
|
||||
/// 现在使用redis作为缓存,不需要将菜单存放至jwt中了
|
||||
@@ -96,18 +99,35 @@ namespace Yi.Framework.WebCore
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置文件下载名称
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="fileName"></param>
|
||||
public static void FileInlineHandle(this HttpContext httpContext, string fileName)
|
||||
{
|
||||
string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.GetEncoding("UTF-8"));
|
||||
httpContext.Response.Headers.Add("Content-Disposition", "inline;filename=" + encodeFilename);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置文件附件名称
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="fileName"></param>
|
||||
public static void FileAttachmentHandle(this HttpContext httpContext, string fileName)
|
||||
{
|
||||
string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.GetEncoding("UTF-8"));
|
||||
httpContext.Response.Headers.Add("Content-Disposition", "attachment;filename=" + encodeFilename);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取语言种类
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetLanguage(this HttpContext httpContext)
|
||||
{
|
||||
string res = "zh-CN";
|
||||
@@ -120,20 +140,13 @@ namespace Yi.Framework.WebCore
|
||||
|
||||
}
|
||||
|
||||
public static string GetBody(this HttpContext httpContext)
|
||||
{
|
||||
if (httpContext.Request.Body != null)
|
||||
{
|
||||
httpContext.Request.EnableBuffering();
|
||||
httpContext.Request.Body.Position = 0;
|
||||
StreamReader stream = new StreamReader(httpContext.Request.Body);
|
||||
return stream.ReadToEndAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取请求Body参数
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reqMethod"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetRequestValue(this HttpContext context, string reqMethod)
|
||||
{
|
||||
string param;
|
||||
@@ -151,5 +164,32 @@ namespace Yi.Framework.WebCore
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户端IP
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetClientIp(this HttpContext context)
|
||||
{
|
||||
if (context == null) return "";
|
||||
var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
result = context.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
if (string.IsNullOrEmpty(result) || result.Contains("::1"))
|
||||
result = "127.0.0.1";
|
||||
|
||||
result = result.Replace("::ffff:", "127.0.0.1");
|
||||
|
||||
//Ip规则效验
|
||||
var regResult = Regex.IsMatch(result, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
|
||||
|
||||
result = regResult ? result : "127.0.0.1";
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yi.Framework.WebCore.MiddlewareExtend
|
||||
{
|
||||
public class HttpBodyMiddleware
|
||||
{
|
||||
|
||||
private readonly RequestDelegate _next;
|
||||
private ILogger<HttpBodyMiddleware> _logger;
|
||||
public HttpBodyMiddleware(RequestDelegate next, ILogger<HttpBodyMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
|
||||
context.Request.EnableBuffering();
|
||||
if (context.Request.Query.TryGetValue("access_token", out var token))
|
||||
{
|
||||
context.Request.Headers.Add("Authorization", $"Bearer {token}");
|
||||
}
|
||||
await _next(context);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class HttpBodyExtend
|
||||
{
|
||||
public static IApplicationBuilder UseHttpBodyService(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<HttpBodyMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user