diff --git a/WebFirst/database/sqlite.db b/WebFirst/database/sqlite.db index 25f2976c..b7d7dd70 100644 Binary files a/WebFirst/database/sqlite.db and b/WebFirst/database/sqlite.db differ diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml index cef7ad07..5b252db1 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Config/SwaggerDoc.xml @@ -336,6 +336,14 @@ + + + 动态条件分页查询 + + + + + 动态条件分页查询 @@ -478,6 +486,13 @@ + + + 操作日志测试 + + + + 用户管理 diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/LoginLogController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/LoginLogController.cs new file mode 100644 index 00000000..7c831f84 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/LoginLogController.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Yi.Framework.Common.Models; +using Yi.Framework.Interface; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; +using Yi.Framework.WebCore; +using Yi.Framework.WebCore.AttributeExtend; +using Yi.Framework.WebCore.AuthorizationPolicy; + +namespace Yi.Framework.ApiMicroservice.Controllers +{ + [ApiController] + [Route("api/[controller]/[action]")] + public class LoginLogController : BaseCrudController + { + private ILoginLogService _iLoginLogService; + public LoginLogController(ILogger logger, ILoginLogService iLoginLogService) : base(logger, iLoginLogService) + { + _iLoginLogService = iLoginLogService; + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OperationLogController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OperationLogController.cs new file mode 100644 index 00000000..86663cba --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/OperationLogController.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Yi.Framework.Common.Models; +using Yi.Framework.Interface; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; +using Yi.Framework.WebCore; +using Yi.Framework.WebCore.AttributeExtend; +using Yi.Framework.WebCore.AuthorizationPolicy; + +namespace Yi.Framework.ApiMicroservice.Controllers +{ + [ApiController] + [Route("api/[controller]/[action]")] + public class OperationLogController : BaseSimpleCrudController + { + private IOperationLogService _iOperationLogService; + public OperationLogController(ILogger logger, IOperationLogService iOperationLogService) : base(logger, iOperationLogService) + { + _iOperationLogService = iOperationLogService; + } + /// + /// 动态条件分页查询 + /// + /// + /// + /// + [HttpGet] + public async Task PageList([FromQuery] OperationLogEntity operationLog, [FromQuery] PageParModel page) + { + return Result.Success().SetData(await _iOperationLogService.SelctPageList(operationLog, page)); + } + + + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/TestController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/TestController.cs index c2bb50e6..72f6bb66 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/TestController.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/TestController.cs @@ -221,6 +221,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers return Result.Success(); } + /// /// 清空数据库 /// @@ -256,5 +257,17 @@ namespace Yi.Framework.ApiMicroservice.Controllers var rep = _iUserService._repository; return Result.Success().SetStatus(DbSeedExtend.Invoer(rep._Db)); } + + /// + /// 操作日志测试 + /// + /// + /// + [HttpPost] + [Log("测试模块", Common.Enum.OperEnum.Insert)] + public Result LogTest(List par) + { + return Result.Success().SetData(par); + } } } diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs index b797f44a..f7674f71 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs @@ -163,6 +163,11 @@ app.UseStaticFiles(); //Թʻע #endregion app.UseLocalizerService(); + +#region +//body +#endregion +app.UseHttpBodyService(); #region //HttpsRedirectionע #endregion diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj index 5a98ed12..6edd784f 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj @@ -34,6 +34,9 @@ Always + + Always + Always diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/ip2region.db b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/ip2region.db new file mode 100644 index 00000000..0fc60e6c Binary files /dev/null and b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/ip2region.db differ diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db index 20cbf7bc..f226bb05 100644 Binary files a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db and b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/yi-sqlsugar-dev.db differ diff --git a/Yi.Framework.Net6/Yi.Framework.Common/Enum/OperationEnum.cs b/Yi.Framework.Net6/Yi.Framework.Common/Enum/OperEnum.cs similarity index 91% rename from Yi.Framework.Net6/Yi.Framework.Common/Enum/OperationEnum.cs rename to Yi.Framework.Net6/Yi.Framework.Common/Enum/OperEnum.cs index 592775f1..ecfd535a 100644 --- a/Yi.Framework.Net6/Yi.Framework.Common/Enum/OperationEnum.cs +++ b/Yi.Framework.Net6/Yi.Framework.Common/Enum/OperEnum.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Yi.Framework.Common.Enum { - public enum OperationEnum + public enum OperEnum { Insert=1, Update=2, diff --git a/Yi.Framework.Net6/Yi.Framework.Common/Yi.Framework.Common.csproj b/Yi.Framework.Net6/Yi.Framework.Common/Yi.Framework.Common.csproj index 02122188..78f348dd 100644 --- a/Yi.Framework.Net6/Yi.Framework.Common/Yi.Framework.Common.csproj +++ b/Yi.Framework.Net6/Yi.Framework.Common/Yi.Framework.Common.csproj @@ -7,6 +7,7 @@ + diff --git a/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs b/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs index 74ecfe3c..0bb2f670 100644 --- a/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs +++ b/Yi.Framework.Net6/Yi.Framework.Core/JwtInvoker.cs @@ -38,7 +38,7 @@ namespace Yi.Framework.Core claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")); claims.Add(new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(minutes)).ToUnixTimeSeconds()}")); claims.Add(new Claim(JwtRegisteredClaimNames.Sid, user.Id.ToString())); - claims.Add(new Claim(JwtRegisteredClaimNames.Name, user.UserName)); + claims.Add(new Claim("userName", user.UserName)); claims.Add(new Claim("deptId", user.DeptId.ToString())); //-----------------------------以下从user的权限表中添加权限-----------------------例如: diff --git a/Yi.Framework.Net6/Yi.Framework.Interface/IOperationLogService.cs b/Yi.Framework.Net6/Yi.Framework.Interface/IOperationLogService.cs new file mode 100644 index 00000000..8e7823c8 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Interface/IOperationLogService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Yi.Framework.Common.Models; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Interface +{ + public partial interface IOperationLogService:IBaseService + { + Task>> SelctPageList(OperationLogEntity operationLog, PageParModel page); + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/ILoginLogService.cs b/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/ILoginLogService.cs new file mode 100644 index 00000000..580bba86 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/ILoginLogService.cs @@ -0,0 +1,9 @@ +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Interface +{ + public partial interface ILoginLogService:IBaseService + { + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/IOperationLogService.cs b/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/IOperationLogService.cs new file mode 100644 index 00000000..54073186 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Interface/IServiceTemplate/IOperationLogService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Yi.Framework.Common.Models; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Interface +{ + public partial interface IOperationLogService : IBaseService + { + + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/LoginLogEntity.cs b/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/LoginLogEntity.cs new file mode 100644 index 00000000..d2165318 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/LoginLogEntity.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +namespace Yi.Framework.Model.Models +{ + /// + /// 登入日志 + /// + [SugarTable("LoginLog")] + public partial class LoginLogEntity:IBaseModelEntity + { + public LoginLogEntity() + { + this.CreateTime = DateTime.Now; + } + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName="Id" ,IsPrimaryKey = true )] + public long Id { get; set; } + /// + /// 登录用户 + /// + [SugarColumn(ColumnName="LoginUser" )] + public string LoginUser { get; set; } + /// + /// 登录地点 + /// + [SugarColumn(ColumnName="LoginLocation" )] + public string LoginLocation { get; set; } + /// + /// 登录Ip + /// + [SugarColumn(ColumnName="LoginIp" )] + public string LoginIp { get; set; } + /// + /// 浏览器 + /// + [SugarColumn(ColumnName="Browser" )] + public string Browser { get; set; } + /// + /// 操作系统 + /// + [SugarColumn(ColumnName="Os" )] + public string Os { get; set; } + /// + /// 登录信息 + /// + [SugarColumn(ColumnName="LogMsg" )] + public string LogMsg { get; set; } + /// + /// 创建者 + /// + [SugarColumn(ColumnName="CreateUser" )] + public long? CreateUser { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnName="CreateTime" )] + public DateTime? CreateTime { get; set; } + /// + /// 修改者 + /// + [SugarColumn(ColumnName="ModifyUser" )] + public long? ModifyUser { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName="ModifyTime" )] + public DateTime? ModifyTime { get; set; } + /// + /// 租户Id + /// + [SugarColumn(ColumnName="TenantId" )] + public long? TenantId { get; set; } + /// + /// 排序字段 + /// + [SugarColumn(ColumnName="OrderNum" )] + public int? OrderNum { get; set; } + /// + /// 描述 + /// + [SugarColumn(ColumnName="Remark" )] + public string Remark { get; set; } + /// + /// 是否删除 + /// + [SugarColumn(ColumnName="IsDeleted" )] + public bool? IsDeleted { get; set; } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/OperationLogEntity.cs b/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/OperationLogEntity.cs new file mode 100644 index 00000000..183e60a3 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Model/ModelsTemplate/OperationLogEntity.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +namespace Yi.Framework.Model.Models +{ + /// + /// 操作日志表 + /// + [SugarTable("OperationLog")] + public partial class OperationLogEntity:IBaseModelEntity + { + public OperationLogEntity() + { + this.CreateTime = DateTime.Now; + } + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName="Id" ,IsPrimaryKey = true )] + public long Id { get; set; } + /// + /// 操作模块 + /// + [SugarColumn(ColumnName="Title" )] + public string Title { get; set; } + /// + /// 操作类型 + /// + [SugarColumn(ColumnName="OperType" )] + public int? OperType { get; set; } + /// + /// 请求方法 + /// + [SugarColumn(ColumnName="RequestMethod" )] + public string RequestMethod { get; set; } + /// + /// 操作人员 + /// + [SugarColumn(ColumnName="OperUser" )] + public string OperUser { get; set; } + /// + /// 操作Ip + /// + [SugarColumn(ColumnName="OperIp" )] + public string OperIp { get; set; } + /// + /// 操作地点 + /// + [SugarColumn(ColumnName="OperLocation" )] + public string OperLocation { get; set; } + /// + /// 操作方法 + /// + [SugarColumn(ColumnName="Method" )] + public string Method { get; set; } + /// + /// 请求参数 + /// + [SugarColumn(ColumnName="RequestParam" )] + public string RequestParam { get; set; } + /// + /// 请求结果 + /// + [SugarColumn(ColumnName="RequestResult" )] + public string RequestResult { get; set; } + /// + /// 创建者 + /// + [SugarColumn(ColumnName="CreateUser" )] + public long? CreateUser { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnName="CreateTime" )] + public DateTime? CreateTime { get; set; } + /// + /// 修改者 + /// + [SugarColumn(ColumnName="ModifyUser" )] + public long? ModifyUser { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName="ModifyTime" )] + public DateTime? ModifyTime { get; set; } + /// + /// 租户Id + /// + [SugarColumn(ColumnName="TenantId" )] + public long? TenantId { get; set; } + /// + /// 排序字段 + /// + [SugarColumn(ColumnName="OrderNum" )] + public int? OrderNum { get; set; } + /// + /// 描述 + /// + [SugarColumn(ColumnName="Remark" )] + public string Remark { get; set; } + /// + /// 是否删除 + /// + [SugarColumn(ColumnName="IsDeleted" )] + public bool? IsDeleted { get; set; } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Model/SeedData/DictionaryInfoSeed.cs b/Yi.Framework.Net6/Yi.Framework.Model/SeedData/DictionaryInfoSeed.cs index 41257184..7b2f998e 100644 --- a/Yi.Framework.Net6/Yi.Framework.Model/SeedData/DictionaryInfoSeed.cs +++ b/Yi.Framework.Net6/Yi.Framework.Model/SeedData/DictionaryInfoSeed.cs @@ -335,7 +335,7 @@ namespace Yi.Framework.Model.SeedData { Id = SnowFlakeSingle.Instance.NextId(), DictLabel = "成功", - DictValue = "0", + DictValue = "false", DictType = "sys_common_status", OrderNum = 100, Remark = "正常状态", @@ -346,7 +346,7 @@ namespace Yi.Framework.Model.SeedData { Id = SnowFlakeSingle.Instance.NextId(), DictLabel = "失败", - DictValue = "1", + DictValue = "true", DictType = "sys_common_status", OrderNum = 99, Remark = "失败状态", diff --git a/Yi.Framework.Net6/Yi.Framework.Service/OperationLogService.cs b/Yi.Framework.Net6/Yi.Framework.Service/OperationLogService.cs new file mode 100644 index 00000000..f2f13014 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Service/OperationLogService.cs @@ -0,0 +1,29 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yi.Framework.Common.Models; +using Yi.Framework.Interface; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Service +{ + public partial class OperationLogService : BaseService, IOperationLogService + { + public async Task>> SelctPageList(OperationLogEntity operationLog, PageParModel page) + { + RefAsync total = 0; + var data = await _repository._DbQueryable + .WhereIF(!string.IsNullOrEmpty(operationLog.Title), u => u.Title.Contains(operationLog.Title)) + .WhereIF(!string.IsNullOrEmpty(operationLog.OperUser), u => u.OperUser.Contains(operationLog.OperUser)) + .WhereIF(operationLog.OperType is not null, u => u.OperType==operationLog.OperType.GetHashCode()) + .WhereIF(operationLog.IsDeleted.IsNotNull(), u => u.IsDeleted == operationLog.IsDeleted) + + .OrderBy(u => u.OrderNum, OrderByType.Desc) + .ToPageListAsync(page.PageNum, page.PageSize, total); + + return new PageModel>(data, total); + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/LoginLogService.cs b/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/LoginLogService.cs new file mode 100644 index 00000000..1c0ed6c8 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/LoginLogService.cs @@ -0,0 +1,14 @@ +using SqlSugar; +using Yi.Framework.Interface; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Service +{ + public partial class LoginLogService : BaseService, ILoginLogService + { + public LoginLogService(IRepository repository) : base(repository) + { + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/OperationLogService.cs b/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/OperationLogService.cs new file mode 100644 index 00000000..2acae0b0 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.Service/ServiceTemplate/OperationLogService.cs @@ -0,0 +1,14 @@ +using SqlSugar; +using Yi.Framework.Interface; +using Yi.Framework.Model.Models; +using Yi.Framework.Repository; + +namespace Yi.Framework.Service +{ + public partial class OperationLogService : BaseService, IOperationLogService + { + public OperationLogService(IRepository repository) : base(repository) + { + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/GlobalLogAttribute.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/GlobalLogAttribute.cs index 78687593..1db516e7 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/GlobalLogAttribute.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/GlobalLogAttribute.cs @@ -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 _logger; + private IOperationLogService _operationLogService; //注入一个日志服务 - public GlobalLogAttribute(ILogger logger) + public GlobalLogAttribute(ILogger 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}"); } } diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/LogAttribute.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/LogAttribute.cs index ea594683..2ead4163 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/LogAttribute.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/AttributeExtend/LogAttribute.cs @@ -13,11 +13,30 @@ namespace Yi.Framework.WebCore.AttributeExtend [AttributeUsage(AttributeTargets.Method)] public class LogAttribute : Attribute { - private OperationEnum OperationType { get; set; } + /// + /// 操作类型 + /// + public OperEnum OperType { get; set; } - public LogAttribute(OperationEnum operationType) + /// + /// 日志标题(模块) + /// + public string Title { get; set; } + + /// + /// 是否保存请求数据 + /// + public bool IsSaveRequestData { get; set; } = true; + + /// + /// 是否保存返回数据 + /// + public bool IsSaveResponseData { get; set; } = true; + + public LogAttribute(string title, OperEnum operationType) { - this.OperationType = operationType; + this.Title = title; + this.OperType = operationType; } } } \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/BuilderExtend/OptionsWritable/Internal/JsonOptionsWritable.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/BuilderExtend/OptionsWritable/Internal/JsonOptionsWritable.cs index 47ee93ff..662976d5 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/BuilderExtend/OptionsWritable/Internal/JsonOptionsWritable.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/BuilderExtend/OptionsWritable/Internal/JsonOptionsWritable.cs @@ -15,12 +15,12 @@ internal class JsonOptionsWritable : FileOptionsWritableBase public override void Update(Action configuration) { - JObject? jObject = JsonConvert.DeserializeObject(File.ReadAllText(this.FileName)); + JObject jObject = JsonConvert.DeserializeObject(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(jtoken.ToString()) ?? new TOptions(); configuration?.Invoke(option); diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend/HttpContextExtend.cs similarity index 75% rename from Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs rename to Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend/HttpContextExtend.cs index f6b28d9a..9192839c 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend/HttpContextExtend.cs @@ -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 { /// /// 判断是否为异步请求 @@ -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; } /// @@ -69,6 +70,8 @@ namespace Yi.Framework.WebCore var p = httpContext; return httpContext.User.Claims.FirstOrDefault(u => u.Type == "permission").Value; } + + /// /// 基于HttpContext,当前鉴权方式解析,获取用户信息 /// 现在使用redis作为缓存,不需要将菜单存放至jwt中了 @@ -96,18 +99,35 @@ namespace Yi.Framework.WebCore }; } + /// + /// 设置文件下载名称 + /// + /// + /// 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); } + + /// + /// 设置文件附件名称 + /// + /// + /// 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); } + + /// + /// 获取语言种类 + /// + /// + /// 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 ""; - - } - + /// + /// 获取请求Body参数 + /// + /// + /// + /// public static string GetRequestValue(this HttpContext context, string reqMethod) { string param; @@ -151,5 +164,32 @@ namespace Yi.Framework.WebCore } return param; } + + + /// + /// 获取客户端IP + /// + /// + /// + 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; + } + } } diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/HttpBodyExtend.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/HttpBodyExtend.cs new file mode 100644 index 00000000..6aa7f52e --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/HttpBodyExtend.cs @@ -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 _logger; + public HttpBodyMiddleware(RequestDelegate next, ILogger 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(); + } + } +} diff --git a/Yi.Vue3.X.RuoYi/src/api/monitor/operlog.js b/Yi.Vue3.X.RuoYi/src/api/monitor/operlog.js index a04bca84..17c3470a 100644 --- a/Yi.Vue3.X.RuoYi/src/api/monitor/operlog.js +++ b/Yi.Vue3.X.RuoYi/src/api/monitor/operlog.js @@ -3,7 +3,7 @@ import request from '@/utils/request' // 查询操作日志列表 export function list(query) { return request({ - url: '/monitor/operlog/list', + url: '/operationLog/pageList', method: 'get', params: query }) @@ -12,15 +12,16 @@ export function list(query) { // 删除操作日志 export function delOperlog(operId) { return request({ - url: '/monitor/operlog/' + operId, - method: 'delete' + url: '/operationLog/delList', + method: 'delete', + data:"string"==typeof(operId)?[operId]:operId }) } // 清空操作日志 export function cleanOperlog() { return request({ - url: '/monitor/operlog/clean', + url: '/operationLog/clear', method: 'delete' }) } diff --git a/Yi.Vue3.X.RuoYi/src/views/monitor/operlog/index.vue b/Yi.Vue3.X.RuoYi/src/views/monitor/operlog/index.vue index 2e782bb7..4e2510c4 100644 --- a/Yi.Vue3.X.RuoYi/src/views/monitor/operlog/index.vue +++ b/Yi.Vue3.X.RuoYi/src/views/monitor/operlog/index.vue @@ -10,18 +10,18 @@ @keyup.enter="handleQuery" /> - + - + - - - - - + + + + + - + - + - + - + - + @@ -147,32 +138,32 @@ {{ form.title }} / {{ typeFormat(form) }} {{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }} + >{{ form.operUser }} / {{ form.operIp }} / {{ form.operLocation }} - {{ form.operUrl }} + {{ form.method }} {{ form.requestMethod }} {{ form.method }} - {{ form.operParam }} + {{ form.requestParam }} - {{ form.jsonResult }} + {{ form.requestResult }} -
正常
-
失败
+
正常
+
失败
- {{ parseTime(form.operTime) }} + {{ parseTime(form.createTime) }} - {{ form.errorMsg }} + {{ form.errorMsg }} @@ -209,9 +200,9 @@ const data = reactive({ pageNum: 1, pageSize: 10, title: undefined, - operName: undefined, - businessType: undefined, - status: undefined + operUser: undefined, + operType: undefined, + isDeleted: undefined } }); @@ -221,8 +212,8 @@ const { queryParams, form } = toRefs(data); function getList() { loading.value = true; list(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { - operlogList.value = response.rows; - total.value = response.total; + operlogList.value = response.data.data; + total.value = response.data.total; loading.value = false; }); } @@ -244,7 +235,7 @@ function resetQuery() { } /** 多选框选中数据 */ function handleSelectionChange(selection) { - ids.value = selection.map(item => item.operId); + ids.value = selection.map(item => item.id); multiple.value = !selection.length; } /** 排序触发事件 */ @@ -260,7 +251,7 @@ function handleView(row) { } /** 删除按钮操作 */ function handleDelete(row) { - const operIds = row.operId || ids.value; + const operIds = row.id || ids.value; proxy.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function () { return delOperlog(operIds); }).then(() => {