develop #2

Merged
zhaozhenj merged 4 commits from develop into master 3 months ago
  1. 17
      src/1.datas/ATS.NonCustodial.Domain/Entities/Log/AppLoginLog.cs
  2. 42
      src/1.datas/ATS.NonCustodial.Domain/Entities/Log/AppOperationLog.cs
  3. 55
      src/2.services/ATS.NonCustodial.Application/Impl/Logs/AuditLogService.cs
  4. 102
      src/2.services/ATS.NonCustodial.Application/Impl/Logs/LoginLogService.cs
  5. 153
      src/2.services/ATS.NonCustodial.Application/Impl/Logs/OperationLogService.cs
  6. 17
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/AuditLog/IAuditLogService.cs
  7. 27
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/ILoginLogService.cs
  8. 25
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Input/LogGetPageDto.cs
  9. 75
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Input/LoginLogAddInput.cs
  10. 47
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Output/LoginLogListOutput.cs
  11. 34
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/IOperationLogService.cs
  12. 85
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/Input/OprationLogAddInput.cs
  13. 77
      src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/Output/OprationLogListOutput.cs
  14. 85
      src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs
  15. 20
      src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs
  16. 175
      src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs

17
src/1.datas/ATS.NonCustodial.Domain/Entities/Log/AppLoginLog.cs

@ -0,0 +1,17 @@
using ATS.NonCustodial.Domain.Shared.AggRootEntities;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace ATS.NonCustodial.Domain.Entities.Logs
{
/// <summary>
/// 登录日志
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-12 18:30 PM
[Table("app_login_log")]
[Index(nameof(CreatedUserId), nameof(CreatedUserName))]
public class AppLoginLog : LogAbstract
{
}
}

42
src/1.datas/ATS.NonCustodial.Domain/Entities/Log/AppOperationLog.cs

@ -0,0 +1,42 @@
using ATS.NonCustodial.Domain.Shared.AggRootEntities;
using ATS.NonCustodial.Domain.Shared.Constants;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ATS.NonCustodial.Domain.Entities.Logs
{
/// <summary>
/// 操作日志
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-12 18:30 PM
[Table("app_operation_log")]
[Index(nameof(CreatedUserId), nameof(CreatedUserName))]
public class AppOperationLog : LogAbstract
{
/// <summary>
/// 接口名称
/// </summary>
[MaxLength(StringLengthConstants.StringLength255)]
public string? ApiLabel { get; set; }
/// <summary>
/// 接口地址
/// </summary>
[MaxLength(StringLengthConstants.StringLength128)]
public string? ApiPath { get; set; }
/// <summary>
/// 接口提交方法
/// </summary>
[MaxLength(StringLengthConstants.StringLength10)]
public string? ApiMethod { get; set; }
/// <summary>
/// 操作参数
/// </summary>
[MaxLength(StringLengthConstants.StringLength2048)]
public string? Params { get; set; }
}
}

55
src/2.services/ATS.NonCustodial.Application/Impl/Logs/AuditLogService.cs

@ -0,0 +1,55 @@
using ATS.NonCustodial.Application.Base;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.AuditLog;
using ATS.NonCustodial.AuditLogging.AuditLoggings.Services;
using ATS.NonCustodial.AuditLogging.Dtos.Input;
using ATS.NonCustodial.AuditLogging.Dtos.Output;
using ATS.NonCustodial.AuditLogging.EntityFrameworkCore.Entities;
using ATS.NonCustodial.AuditLogging.Mappers;
using ATS.NonCustodial.DynamicApi;
using ATS.NonCustodial.DynamicApi.Attributes;
using Microsoft.AspNetCore.Mvc;
namespace ATS.NonCustodial.Application.Impl.Logs
{
/// <summary>
/// 审计日志服务
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-04-25 16:31
[DynamicApi(Area = "admin")]
public class AuditLogService : AdminAppServiceBase, IAuditLogService, IDynamicApi
{
#region Identity
protected readonly IAuditLogRepository<AuditLog> AuditLogRepository;
public AuditLogService(IAuditLogRepository<AuditLog> auditLogRepository)
{
AuditLogRepository = auditLogRepository;
}
#endregion Identity
/// <summary>
/// 查询
/// </summary>
/// <param name="filters"></param>
/// <returns></returns>
[HttpPost]
public async Task<AuditLogsDto> GetAsync(AuditLogFilterDto filters)
{
var pagedList = await AuditLogRepository.GetAsync(filters.Event, filters.Source, filters.Category, filters.Created, filters.SubjectIdentifier, filters.SubjectName, filters.Page, filters.PageSize);
var auditLogsDto = pagedList.ToAuditLogModel();
return auditLogsDto;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="deleteOlderThan"></param>
/// <returns></returns>
[HttpDelete]
public virtual async Task DeleteLogsOlderThanAsync(DateTime deleteOlderThan) => await AuditLogRepository.DeleteLogsOlderThanAsync(deleteOlderThan);
}
}

102
src/2.services/ATS.NonCustodial.Application/Impl/Logs/LoginLogService.cs

@ -0,0 +1,102 @@
using ATS.NonCustodial.Application.Base;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Output;
using ATS.NonCustodial.Domain.Entities.Logs;
using ATS.NonCustodial.Domain.Shared.OrmRepositories.Basic.EfCore;
using ATS.NonCustodial.DynamicApi;
using ATS.NonCustodial.DynamicApi.Attributes;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
using ATS.NonCustodial.Shared.Extensions;
using ATS.NonCustodial.Shared.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ATS.NonCustodial.Application.Impl.Logs
{
/// <summary>
/// 登录日志服务
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-17 10:15 PM
[DynamicApi(Area = "admin")]
public class LoginLogService : AdminAppServiceBase, ILoginLogService, IDynamicApi
{
#region Identity
private readonly IHttpContextAccessor _context;
private readonly IEfRepository<AppLoginLog?, long> _loginLogRepository;
public LoginLogService(
IHttpContextAccessor context,
IEfRepository<AppLoginLog?, long> loginLogRepository
)
{
_context = context;
_loginLogRepository = loginLogRepository;
}
#endregion Identity
/// <summary>
/// 查询登录日志列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResultOutput> GetPageAsync(LogGetPageDto input)
{
var express = GetExpression(input, _loginLogRepository.AsQueryable(false, true));
var rtn = await base.GetPageAsync<AppLoginLog, LogGetPageDto, LoginLogListOutput>(input, express);
return ResultOutput.Ok(rtn);
}
/// <summary>
/// 新增
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<IResultOutput<long>> AddAsync(LoginLogAddInput input)
{
var res = new ResultOutput<long>();
input.IP = IPHelper.GetIP(_context?.HttpContext?.Request);
string ua = _context.HttpContext.Request.Headers["User-Agent"];
if (ua.NotNull())
{
var client = UAParser.Parser.GetDefault().Parse(ua);
var device = client.Device.Family;
device = device.ToLower() == "other" ? "" : device;
input.Browser = client.UA.Family;
input.Os = client.OS.Family;
input.Device = device;
input.BrowserInfo = ua;
}
var entity = Mapper.Map<AppLoginLog>(input);
var id = (await _loginLogRepository.InsertAsync(entity)).Id;
return id > 0 ? res.Ok(id) : res;
}
#region Private
/// <summary>
/// 查询条件
/// </summary>
/// <param name="pageInput"></param>
/// <param name="query"></param>
/// <returns></returns>
private IQueryable<AppLoginLog> GetExpression(LogGetPageDto pageInput, IQueryable<AppLoginLog?> query)
{
query = query
.WhereIf(pageInput.OperatorName.NotNull(), w => pageInput.OperatorName.Contains(w.CreatedUserName));
var express = base.GetEntityAddExpression<AppLoginLog, LogGetPageDto, long>(pageInput, query);
return express;
}
#endregion Private
}
}

153
src/2.services/ATS.NonCustodial.Application/Impl/Logs/OperationLogService.cs

@ -0,0 +1,153 @@
using ATS.NonCustodial.Application.Base;
using ATS.NonCustodial.Application.Contracts.Interfaces.Business.AppCaseManagements.AppCaseManagement;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Input;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Output;
using ATS.NonCustodial.Domain.Entities.Logs;
using ATS.NonCustodial.Domain.Shared.AggRootEntities.Dtos;
using ATS.NonCustodial.Domain.Shared.OrmRepositories.Basic.EfCore;
using ATS.NonCustodial.DynamicApi;
using ATS.NonCustodial.DynamicApi.Attributes;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
using ATS.NonCustodial.Shared.Extensions;
using AutoMapper.QueryableExtensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace ATS.NonCustodial.Application.Impl.Logs
{
/// <summary>
/// 操作日志服务
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-17 10:11 PM
[DynamicApi(Area = "admin")]
public class OperationLogService : AdminAppServiceBase, IOperationLogService, IDynamicApi
{
#region Identity
private readonly IHttpContextAccessor _context;
private readonly IEfRepository<AppOperationLog?, long> _oprationLogRepository;
private readonly IAppCaseManagementService _appCaseManagementService;
public OperationLogService(
IHttpContextAccessor context,
IEfRepository<AppOperationLog?, long> oprationLogRepository,
IAppCaseManagementService appCaseManagementService
)
{
_context = context;
_oprationLogRepository = oprationLogRepository;
_appCaseManagementService = appCaseManagementService;
}
#endregion Identity
/// <summary>
/// 查询操作日志列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResultOutput> GetPageAsync(LogGetPageDto input)
{
var express = await GetExpression(input, _oprationLogRepository.AsQueryable(false, true).Take(3000));
var rtn = await base.GetPageAsync<AppOperationLog, LogGetPageDto, OprationLogListOutput>(input, express);
return ResultOutput.Ok(rtn);
}
/// <summary>
/// 查询操作日志明细
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<IResultOutput> Get(long id)
{
var rtn = await base.GetAsync<AppOperationLog, OprationLogListOutput, long>(_oprationLogRepository, id);
return ResultOutput.Ok(rtn);
}
/// <summary>
/// 新增
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<IResultOutput> AddAsync(OprationLogAddInput input)
{
string ua = _context.HttpContext!.Request.Headers["User-Agent"];
var client = UAParser.Parser.GetDefault().Parse(ua);
var device = client.Device.Family;
device = device.ToLower() == "other" ? "" : device;
input.Browser = client.UA.Family;
input.Os = client.OS.Family;
input.Device = device;
input.BrowserInfo = ua;
input.NickName = User.NickName;
input.IpAddress = _context.HttpContext.Connection.RemoteIpAddress?.ToString().Replace("::ffff:", "")/*IPHelper.GetIP(_context?.HttpContext?.Request)*/;
var entity = Mapper.Map<AppOperationLog>(input);
var id = ((await _oprationLogRepository.InsertAsync(entity))!).Id;
return ResultOutput.Result(id > 0);
}
/// <summary>
/// 业务工作台==>最新5条操作日志
/// </summary>
/// <returns></returns>
public async Task<IResultOutput> OperationBusinessWorkbench()
{
var userIds = await _appCaseManagementService.GetUserIdListByCurrentUser();
var dataList = await _oprationLogRepository.AsQueryable(false, true)
.Where(w => w.CreatedUserId != null && userIds.Contains(w.CreatedUserId.Value))
.OrderByDescending(w => w.CreatedTime)
.Skip(0)
.Take(5)
.ProjectTo<OprationLogListOutput>(Mapper.ConfigurationProvider)
.ToListAsync();
return ResultOutput.Ok(dataList);
}
/// <summary>
/// 批量删除操作日志
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<IResultOutput> BatchDeleteAsync(BatchIdsInput input)
{
var rtn = await _oprationLogRepository.DeleteAsync(w => input.Ids.Contains(w.Id));
return ResultOutput.Ok(rtn > 0);
}
#region Private
/// <summary>
/// 查询条件
/// </summary>
/// <param name="pageInput"></param>
/// <param name="query"></param>
/// <returns></returns>
private async Task<IQueryable<AppOperationLog>> GetExpression(LogGetPageDto pageInput, IQueryable<AppOperationLog?> query)
{
var userIds = await _appCaseManagementService.GetUserIdListByCurrentUser();
query = query
.Where(w => w.CreatedUserId != null && userIds.Contains(w.CreatedUserId.Value))
.WhereIf(pageInput.OperatorName.NotNull(), w => w.CreatedUserName.Contains(pageInput.OperatorName))
.WhereIf(pageInput.Device.NotNull(), w => w.Device==pageInput.Device)
.WhereIf(pageInput.NickName.NotNull(), w => w.NickName==pageInput.NickName);
var express = base.GetEntityAddExpression<AppOperationLog, LogGetPageDto, long>(pageInput, query);
return express;
}
#endregion Private
}
}

17
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/AuditLog/IAuditLogService.cs

@ -0,0 +1,17 @@
using ATS.NonCustodial.AuditLogging.Dtos.Input;
using ATS.NonCustodial.AuditLogging.Dtos.Output;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.AuditLog
{
/// <summary>
///
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-04-25 16:23
public interface IAuditLogService
{
Task<AuditLogsDto> GetAsync(AuditLogFilterDto filters);
Task DeleteLogsOlderThanAsync(DateTime deleteOlderThan);
}
}

27
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/ILoginLogService.cs

@ -0,0 +1,27 @@
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog
{
/// <summary>
/// µÇ¼ÈÕÖ¾½Ó¿Ú
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public interface ILoginLogService
{
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<IResultOutput> GetPageAsync(LogGetPageDto input);
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<IResultOutput<long>> AddAsync(LoginLogAddInput input);
}
}

25
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Input/LogGetPageDto.cs

@ -0,0 +1,25 @@
using ATS.NonCustodial.Shared.Common.Dtos;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input
{
/// <summary>
///
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public class LogGetPageDto : PageRequestBaseInput
{
/// <summary>
/// 操作者名称
/// </summary>
public string? OperatorName { get; set; }
/// <summary>
/// 手机型号
/// </summary>
public string? Device { get; set; }
/// <summary>
/// app
/// </summary>
public string? NickName { get; set; }
}
}

75
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Input/LoginLogAddInput.cs

@ -0,0 +1,75 @@
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input
{
/// <summary>
/// 添加
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public class LoginLogAddInput
{
/// <summary>
/// 租户Id
/// </summary>
public long? TenantId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// IP
/// </summary>
public string? IP { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string? Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string? Os { get; set; }
/// <summary>
/// 设备
/// </summary>
public string? Device { get; set; }
/// <summary>
/// 浏览器信息
/// </summary>
public string? BrowserInfo { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public long ElapsedMilliseconds { get; set; }
/// <summary>
/// 操作状态
/// </summary>
public bool? Status { get; set; }
/// <summary>
/// 操作消息
/// </summary>
public string? Msg { get; set; }
/// <summary>
/// 操作结果
/// </summary>
public string? Result { get; set; }
/// <summary>
/// 创建者Id
/// </summary>
public long? CreatedUserId { get; set; }
/// <summary>
/// 创建者
/// </summary>
public string? CreatedUserName { get; set; }
}
}

47
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/LoginLog/Output/LoginLogListOutput.cs

@ -0,0 +1,47 @@
using ATS.NonCustodial.Domain.Shared.AggRootEntities;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Output
{
/// <summary>
/// 登录日志输出Dto
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public class LoginLogListOutput : EntityFull
{
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// IP
/// </summary>
public string? IP { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string? Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string? Os { get; set; }
/// <summary>
/// 设备
/// </summary>
public string? Device { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public long ElapsedMilliseconds { get; set; }
/// <summary>
/// 操作消息
/// </summary>
public string? Msg { get; set; }
}
}

34
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/IOperationLogService.cs

@ -0,0 +1,34 @@
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.LoginLog.Input;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Input;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog
{
/// <summary>
/// 操作日志接口
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public interface IOperationLogService
{
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<IResultOutput> GetPageAsync(LogGetPageDto input);
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<IResultOutput> AddAsync(OprationLogAddInput input);
/// <summary>
/// 业务工作台==>最新5条操作日志
/// </summary>
/// <returns></returns>
Task<IResultOutput> OperationBusinessWorkbench();
}
}

85
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/Input/OprationLogAddInput.cs

@ -0,0 +1,85 @@
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Input
{
/// <summary>
/// 添加
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public class OprationLogAddInput
{
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 接口名称
/// </summary>
public string? ApiLabel { get; set; }
/// <summary>
/// 接口地址
/// </summary>
public string? ApiPath { get; set; }
/// <summary>
/// 接口提交方法
/// </summary>
public string? ApiMethod { get; set; }
/// <summary>
/// IP
/// </summary>
public string? IpAddress { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string? Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string? Os { get; set; }
/// <summary>
/// 设备
/// </summary>
public string? Device { get; set; }
/// <summary>
/// 浏览器信息
/// </summary>
public string? BrowserInfo { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public long ElapsedMilliseconds { get; set; }
/// <summary>
/// 操作状态
/// </summary>
public bool? Status { get; set; }
/// <summary>
/// 操作消息
/// </summary>
public string? Msg { get; set; }
/// <summary>
/// 操作参数
/// </summary>
public string? Params { get; set; }
/// <summary>
/// 操作结果
/// </summary>
public string? Result { get; set; }
/// <summary>
/// 异常信息
/// </summary>
public string? Exception { get; set; }
}
}

77
src/3.contracts/ATS.NonCustodial.Application.Contracts/Interfaces/Logs/OprationLog/Output/OprationLogListOutput.cs

@ -0,0 +1,77 @@
using ATS.NonCustodial.Domain.Shared.AggRootEntities;
namespace ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Output
{
/// <summary>
/// OprationLogListOutput
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-14 09:32 PM
public class OprationLogListOutput : EntityFull
{
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 接口名称
/// </summary>
public string? ApiLabel { get; set; }
/// <summary>
/// 接口地址
/// </summary>
public string? ApiPath { get; set; }
/// <summary>
/// 接口提交方法
/// </summary>
public string? ApiMethod { get; set; }
/// <summary>
/// IpAddress
/// </summary>
public string? IpAddress { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string? Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string? Os { get; set; }
/// <summary>
/// 设备
/// </summary>
public string? Device { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public long ElapsedMilliseconds { get; set; }
/// <summary>
/// 操作消息
/// </summary>
public string? Msg { get; set; }
/// <summary>
/// 操作参数
/// </summary>
public string? Params { get; set; }
/// <summary>
/// 操作结果
/// </summary>
public string? Result { get; set; }
/// <summary>
/// 异常信息
/// </summary>
public string? Exception { get; set; }
}
}

85
src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ApiHelper.cs

@ -0,0 +1,85 @@
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Api;
using ATS.NonCustodial.Application.Contracts.Interfaces.Admins.Api.Output;
using ATS.NonCustodial.Shared.Common.Attributes;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
using ATS.NonCustodial.Shared.Extensions;
namespace ATS.NonCustodial.AdminUi.Helpers.Logs
{
/// <summary>
/// Api帮助类
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-18 09:46 AM
[SingleInstance]
public class ApiHelper
{
#region Identity
private List<ApiHelperDto> _apis;
private static readonly object LockObject = new();
private readonly IApiService _apiService;
public ApiHelper(IApiService apiService)
{
_apiService = apiService;
}
#endregion Identity
/// <summary>
/// 主要是在Action 操作的时候添加操作日志时候用
/// </summary>
/// <returns></returns>
public List<ApiHelperDto> GetApis()
{
if (_apis != null && _apis.Any()) return _apis;
lock (LockObject)
{
if (_apis != null && _apis.Any()) return _apis;
_apis = new List<ApiHelperDto>();
var apis = ((ResultOutput<List<ApiListOutput>>)_apiService.GetListAsync("").Result)
.Data
.Select(a => new
{
a.Id,
a.ParentId,
a.Label,
a.Path
});
foreach (var api in apis)
{
var parentLabel = apis.FirstOrDefault(a => a.Id == api.ParentId)?.Label;
_apis.Add(new ApiHelperDto
{
Label = parentLabel.NotNull() ? $"{parentLabel} / {api.Label}" : api.Label,
Path = api.Path?.ToLower().Trim('/')
});
}
return _apis;
}
}
}
/// <summary>
///
/// </summary>
public class ApiHelperDto
{
/// <summary>
/// 接口名称
/// </summary>
public string Label { get; set; }
/// <summary>
/// 接口地址
/// </summary>
public string Path { get; set; }
}
}

20
src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/ILogHandler.cs

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Filters;
namespace ATS.NonCustodial.AdminUi.Helpers.Logs
{
/// <summary>
/// 操作日志处理接口
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-18 09:46 AM
public interface ILogHandler
{
/// <summary>
/// 写操作日志
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next);
}
}

175
src/5.shared/ATS.NonCustodial.AdminUi/Helpers/Logs/LogHandler.cs

@ -0,0 +1,175 @@
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog;
using ATS.NonCustodial.Application.Contracts.Interfaces.Logs.OprationLog.Input;
using ATS.NonCustodial.AuditLogging.AuditLoggings.Services;
using ATS.NonCustodial.Shared.Common.UnifiedResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Reflection;
namespace ATS.NonCustodial.AdminUi.Helpers.Logs
{
/// <summary>
/// 控制器操作日志记录 ==> 操作日志处理
/// </summary>
/// Author:mxg
/// CreatedTimed:2022-05-18 09:46 AM
public class LogHandler : ILogHandler
{
#region Identity
private readonly ILogger _logger;
private readonly ApiHelper _apiHelper;
private readonly IOperationLogService _operationLogService;
private readonly IAuditEventLogger _auditEventLogger;
public LogHandler(
ILogger<LogHandler> logger,
ApiHelper apiHelper,
IOperationLogService operationLogService,
IAuditEventLogger auditEventLogger
)
{
_logger = logger;
_apiHelper = apiHelper;
_operationLogService = operationLogService;
_auditEventLogger = auditEventLogger;
}
#endregion Identity
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var sw = new Stopwatch();
sw.Start();
//调用接口
var actionExecutedContext = await next();
sw.Stop();
try
{
//接口Type
var controllerType = (context.ActionDescriptor as ControllerActionDescriptor)?.ControllerTypeInfo.AsType().GetSummary();
//方法信息
var controllerAction = (context.ActionDescriptor as ControllerActionDescriptor)?.MethodInfo.GetSummary();
var input = new OprationLogAddInput
{
ApiLabel = $"{controllerType}/{controllerAction}".Trim('/'),
ApiMethod = context.HttpContext.Request.Method.ToLower(),
ApiPath = context.ActionDescriptor.AttributeRouteInfo?.Template?.ToLower(),
ElapsedMilliseconds = sw.ElapsedMilliseconds,
Params = JsonConvert.SerializeObject(context.ActionArguments)
};
if (actionExecutedContext.Result is ObjectResult { Value: IResultOutput res })
{
input.Status = res.Success;
input.Msg = res.Msg;
}
#region 设置参数
//switch (context.HttpContext.Request.Method)
//{
// case "GET":
// case "DELETE":
// input.Params = context.HttpContext.Request.Path;
// break;
// case "PUT":
// case "POST":
// context.HttpContext.Request.EnableBuffering();
// context.HttpContext.Request.Body.Position = 0;
// StreamReader reader = new StreamReader(context.HttpContext.Request.Body, Encoding.UTF8);
// input.Params = reader.ReadToEndAsync().GetAwaiter().GetResult();
// context.HttpContext.Request.Body.Position = 0;
// break;
// default: break;
//}
//if (input.Params is { Length: > 1024 })
//{
// input.Params = input.Params.Substring(0, 1021) + "...";
//}
#endregion 设置参数
#region 设置返回值
try
{
if (actionExecutedContext.Exception != null && !actionExecutedContext.ExceptionHandled)
{
input.Exception = actionExecutedContext.Exception.StackTrace;
}
}
catch (Exception ex)
{
input.Exception = ex.StackTrace;
throw;
}
finally
{
if (input.Exception is { Length: > 2048 })
{
input.Exception = input.Exception.Substring(0, 2045) + "...";
}
if (actionExecutedContext != null)
{
input.Result = actionExecutedContext.Result switch
{
ObjectResult objectResult => JsonConvert.SerializeObject(objectResult.Value),
JsonResult jsonResult => JsonConvert.SerializeObject(jsonResult.Value),
ContentResult contentResult => contentResult.Content,
_ => input.Result
};
if (input.Result is { Length: > 2048 })
{
input.Result = input.Result.Substring(0, 2045) + "...";
}
}
}
#endregion 设置返回值
//接口名称
//input.ApiLabel = _apiHelper.GetApis().FirstOrDefault(a => a.Path == input.ApiPath)?.Label;
//添加操作日志
await _operationLogService.AddAsync(input);
#region 添加审计日志
//var apiAuditLog = new CustomizedLogEvent()
//{
// Category = nameof(CustomizedLogEvent),
// SubjectType = AuditSubjectTypes.machine,
// SubjectName = Environment.MachineName,
// SubjectIdentifier = Environment.MachineName,
// Action = new { Method = input.ApiPath, Class = context.Controller.ToString() }
//};
//await _auditEventLogger.LogEventAsync(apiAuditLog, options =>
//{
// options.UseDefaultSubject = false;
// options.UseDefaultAction = false;
//});
#endregion 添加审计日志
}
catch (Exception ex)
{
_logger.LogError("操作日志插入异常:{@ex}", ex);
}
}
}
}
Loading…
Cancel
Save