ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理

我们了解ABP框架内部自动记录审计日志和登录日志的,但是这些信息只是在相关的内部接口里面进行记录,并没有一个管理界面供我们了解,但是其系统数据库记录了这些数据信息,我们可以为它们设计一个查看和导出这些审计日志和登录日志的管理界面。本篇随笔继续ABP框架的系列介绍,一步步深入了解ABP框架的应用开发,介绍审计日志和登录日志的管理。1、审计日志和登录日志的基础审计日志,设置我们在访问或者调用某个应用服...

ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理

我们了解ABP框架内部自动记录审计日志和登录日志的,但是这些信息只是在相关的内部接口里面进行记录,并没有一个管理界面供我们了解,但是其系统数据库记录了这些数据信息,我们可以为它们设计一个查看和导出这些审计日志和登录日志的管理界面。本篇随笔继续ABP框架的系列介绍,一步步深入了解ABP框架的应用开发,介绍审计日志和登录日志的管理。

1、审计日志和登录日志的基础

审计日志,设置我们在访问或者调用某个应用服务层接口的时候,横切面流下的一系列操作记录,其中记录我们访问的服务接口,参数,客户端IP地址,访问时间,以及异常等信息,这些操作都是在ABP系统自动记录的,如果我们需要屏蔽某些服务类或者接口,则这些就不会记录在里面,否则默认是记录的。

登录日志,这个就是用户尝试登录的时候,留下的记录信息,其中包括用户的登录用户名,ID,IP地址、登录时间,以及登录是否成功的状态等信息。

我们查看系统数据库,可以看到对应这两个部分的日志表,如下所示。

在ABP框架内部基础项目Abp里面,我们可以看到对应的领域对象实体和Store管理类,不过并没有在应用层的对应服务和相关的DTO,我们需要实现一个审计日志和登陆日志的管理功能界面,界面效果如下所示。

我们搜索ABP项目,查找到审计日志的相关类(包含领域对象实体和Store管理类),如下界面截图。

同样对于系统登录日志对象,我们查找到对应的领域实体和对应的Manger业务逻辑类。

这些也就代表它们都有底层的实现,但是没有服务层应用和DTO对象,因此我们需要扩展这些内容才能够管理显示这些记录信息。

前面介绍过,默认的一般应用服务层和接口,都是会进行审计记录写入的,如果我们需要屏蔽某些应用服务层或者接口,不进行审计信息的记录,那么需要使用特性标记[DisableAuditing]来管理。

如我们针对审计日志应用层接口的访问,我们不想让它多余的记录,那么就设置这个标记即可。

或者屏蔽某些接口

另外,如果我们不想公布某些特殊的接口访问,那么我们可以通过标记 [RemoteService(false)] 进行屏蔽,这样在Web API层就不会公布对应的接口了。

如对于审计日志的记录,增删改我们都不允许客户端进行操作,那么我们把对应的应用服务层接口屏蔽即可。

2、系统审计日志和登录日志的完善

前面介绍了,审计日志和登陆日志的处理,Abp系统只是做了一部分底层的内容,我们如果进行这些信息的管理,我们需要完善它,增加对应的DTO类和应用服务层接口和接口实现。

首先我们根据底层的领域实体对象的属性,复制过来作为对应DTO对象的属性,并增加对应的分页条件DTO对象,由于我们不需要进行创建,因此不需要增加Create***Dto对象类。

如对于审计日志的DTO对象,我们定义如下所示(主要复制领域对象的属性)。

而分页处理的DTO对象如下所示,我们主要增加一个用户名和创建时间区间的条件。

对于登录日志的DTO对象,我们依葫芦画瓢,也是如此操作即可。

登录日志的分页对象Dto如下所示、

完善了这些DTO对象,下一步我们需要创建对应的应用服务层类,这样我们才能在客户端通过Web API获取对应的数据。

首先我们来定义审计日志应用服务类,如下所示。

 [DisableAuditing] //屏蔽这个AppService的审计功能 [AbpAuthorize] public class AuditLogAppService : AsyncCrudAppService<AuditLog, AuditLogDto, long, AuditLogPagedDto>, IAuditLogAppService<AuditLogDto, long, AuditLogPagedDto> {  private readonly IRepository<AuditLog, long> _repository;  private readonly IAuditingStore _stroe;  private readonly IRepository<User, long> _userRepository;  public AuditLogAppService(IRepository<AuditLog, long> repository, IAuditingStore stroe, IRepository<User, long> userRepository) : base(repository)  {_repository = repository;_stroe = stroe;_userRepository = userRepository;  }......

其中我们需要IRepository<User, long>用来转义用户ID为对应的用户名,这样对于我们显示有帮助。

默认来说,这个应用服务层已经具有常规的增删改查、分页等基础接口了,但是我们不需要对外公布增删改接口,我们需要重写实现把它屏蔽。

  /// <summary>  /// 屏蔽创建接口  /// </summary>  [RemoteService(false)]  public override Task<AuditLogDto> Create(AuditLogDto input)  {return base.Create(input);  }  /// <summary>  /// 屏蔽更新接口  /// </summary>  [RemoteService(false)]  public override Task<AuditLogDto> Update(AuditLogDto input)  {return base.Update(input);  }  /// <summary>  /// 屏蔽删除接口  /// </summary>  [RemoteService(false)]  public override Task Delete(EntityDto<long> input)  {return base.Delete(input);  }

那么我们就剩下GetAll和Get两个方法了,我们如果不需要转义特殊内容,我们就可以不重写它,但是我们这里需要对用户ID转义为用户名称,那么需要进行一个处理,如下所示。

  [DisableAuditing]  public override Task<PagedResultDto<AuditLogDto>> GetAll(AuditLogPagedDto input)  {var result = base.GetAll(input);foreach (var item in result.Result.Items){ ConvertDto(item);//对用户名称进行解析}return result;  }  [DisableAuditing]  public override Task<AuditLogDto> Get(EntityDto<long> input)  {var result = base.Get(input);ConvertDto(result.Result);return result;  }  /// <summary>  /// 对记录进行转义  /// </summary>  /// <param name="item">dto数据对象</param>  /// <returns></returns>  protected virtual void ConvertDto(AuditLogDto item)  {//用户名称转义if (item.UserId.HasValue){  item.UserName = _userRepository.Get(item.UserId.Value).UserName;}//IP地址转义if (!string.IsNullOrEmpty(item.ClientIpAddress)){ item.ClientIpAddress = item.ClientIpAddress.Replace("::1", "127.0.0.1");}  }

这里主要就用户ID和IP地址进行一个正常的转义处理,这个也是我们常规接口需要处理的一种常见的情况之一。

排序我们是以执行时间进行排序,倒序显示即可,因此重写排序函数。

  /// <summary>  /// 自定义排序处理  /// </summary>  /// <param name="query"></param>  /// <param name="input"></param>  /// <returns></returns>  protected overrid
源文地址:https://www.guoxiongfei.cn/cntech/19352.html