如何审核角色删除?

How to audit role removals?

从用户中删除角色后,我需要跟踪是谁做的(即哪个 AbpUser)以及他们何时做的。

显而易见的解决方案是重新定义 UserRole 实体,使其继承自 FullAuditedEntity 而不是 CreationAuditedEntity,但 UserRole 实体是在 nuget 包中定义的,所以我不能简单地更改定义。

有没有办法实现我没有看到的这种行为?

这是我到目前为止尝试过的方法。

方法 1:我尝试通过在 AbpUserRole table 上设置删除触发器来在数据库级别处理此问题,这会将记录插入 AbpUserRoleDeleted table,但我想不出一种找出哪个 AbpUser 使用这种方法进行删除的方法。我只能跟踪操作发生的时间。

方法 2:我尝试侦听 UserRole 实体上的 EntityDeleted 域事件,但它似乎没有被触发。有趣的是,当我从用户中删除角色时会触发 EntityUpdated 事件,但即使假设此事件只会在删除 UserRole 时触发,事件数据仍然不包括删除的人。如果是这样,我可以手动将审计信息保存在单独的 table 中,就像数据库删除触发器一样,但这次我将拥有负责删除的 AbpUser。

方法 3:我尝试按照 here 的步骤扩展 UserRole 实体。我能够实现 IDeletionAudited 接口并生成在 AbpUserRoles table 上创建关联列的迁移,但是从用户中删除角色执行的是硬删除而不是软删除,所以我无法判断列甚至会被填充。我假设他们没有。

方法 4:我尝试为 UserRole 实体启用实体历史记录,但它似乎只跟踪创建 UserRole 实体的时间。

这似乎工作正常。

//src\aspnet-core\src\Company.App.EntityFrameworkCore\EntityFrameworkCore\AppDbContext.cs
namespace Company.App.EntityFrameworkCore
{
    public class AppDbContext : AbpZeroDbContext<Tenant, Role, User, AppDbContext>, IAbpPersistedGrantDbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {
            ChangeTracker.StateChanged += OnEntityStateChanged;
        }

        private void OnEntityStateChanged(object sender, EntityStateChangedEventArgs e)
        {
            if (e.Entry.Entity is UserRole && e.NewState == EntityState.Deleted)
            {
                //update instead of delete
                e.Entry.State = EntityState.Modified;
                e.Entry.CurrentValues["IsDeleted"] = true;
                e.Entry.CurrentValues["DeletionTime"] = DateTime.Now;
                e.Entry.CurrentValues["DeleterUserId"] = AbpSession.UserId;
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //use query filter on the `IsDeleted` shadow property
            modelBuilder.Entity<UserRole>().HasQueryFilter(p => !EF.Property<bool>(p, "IsDeleted"));
            modelBuilder.Entity<UserRole>().Property<bool>("IsDeleted");
            modelBuilder.Entity<UserRole>().Property<DateTime?>("DeletionTime").IsRequired(false);
            modelBuilder.Entity<UserRole>().Property<long?>("DeleterUserId").IsRequired(false);
        }
    }
}