Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC
Open Closed

How to audit role removals? #8871


User avatar
0
tom.ohle created

Hello,

When a role is removed from a user, we need to track who did it (ie. which AbpUser) and when they did it.

The obvious solution is to redefine the UserRole entity so that it inherits from FullAuditedEntity instead of CreationAuditedEntity, but the UserRole entity is defined in a nuget package so we cannot simply change the definition.

Is there a way to achieve this behavior that I am not seeing?

Also, in this post ismcagdas said "You cannot change UserRole to SoftDelete".

Is this also because the UserRole entity is defined in a nuget package, or is there another reason it cannot be done?

Here is what I have tried so far.

Approach 1: I tried handling this at the database level by setting up a delete trigger on the AbpUserRole table which would insert a record into a AbpUserRoleDeleted table, but I can't think of a way to find out which AbpUser made the deletion with this approach. I can only track when the action happened.

Approach 2: I tried listening for the EntityDeleted domain event on UserRole entities, but it does not seem to get triggered. Interestingly, the EntityUpdated event is triggered when I remove a role from a user, but even assuming that this event would only ever be triggered when a UserRole is deleted, the event data still does not include who made the deletion. If it did, I could manually save the audit information in a separate table just like a database delete trigger would, but this time I would have the AbpUser that was responsible for the deletion.

Approach 3: I tried extending the UserRole entity by following the steps here. I was able to implement the IDeletionAudited interface and generate a migration that creates the associated columns on the AbpUserRoles table, but removing a role from a user performs a hard delete instead of a soft delete so I can't tell if the columns even get populated. I am assuming they do not.

Approach 4: I tried enabling Entity History for the UserRole entity, but it seems to only track when a UserRole entity is created.

I will continue exploring more approaches, but in the meantime I would appreciate any help you can provide with this problem.

Thanks!


10 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    Approach 2: I tried listening for the EntityDeleted domain event on UserRole entities, but it does not seem to get triggered. Interestingly, the EntityUpdated event is triggered when I remove a role from a user, but even assuming that this event would only ever be triggered when a UserRole is deleted,

    This is a solution, but because of some changes in EF Core3.x, the event has not been triggered, I will check it.

  • User Avatar
    0
    tom.ohle created

    Hi maliming,

    The project has been built upon the "<PROJECTNAME>-aspnetzero-7.3.1" ZIP archive and is still using EF Core 2.2.6.

    ~~Also, I couldn't find a way to get the user behind any of the entity events. Is this even possible?~~

    ~~I found out I can inject AbpSession to get the current user.~~

    Turns out AbpSession is already part of the base class.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @tom.ohle

    Does this happen when you remove a role from user in User Edit Modal ?

  • User Avatar
    0
    tom.ohle created

    Hi @ismcagdas,

    Yes. When I uncheck a role from the Roles tab in the User Edit modal neither the EntityDeleted or EntityDeleting event handlers are called.

    However, the EntityUpdated event is triggered, but I have some concerns about using this event to detect deletions (see my original post).

  • User Avatar
    0
    ismcagdas created
    Support Team

    @tom.ohle

    Thanks, I will check it.

  • User Avatar
    0
    tom.ohle created

    I was able to successfully implement the following solution. Do you see any red flags?

    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)
                {
                    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)
            {
                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);
            }
        }
    }
    
    
  • User Avatar
    0
    maliming created
    Support Team

    hi tom.ohle

    We should check why the event of deleting the entity is not triggered.

    What is your abp version?

  • User Avatar
    0
    tom.ohle created

    The project has been built upon the "<PROJECTNAME>-aspnetzero-7.3.1" ZIP archive and is still using EF Core 2.2.6.

  • User Avatar
    0
    maliming created
    Support Team

    @tom.ohle

    I assume you did not upgrade the abp package, I will check it, thank you.

  • User Avatar
    0
    maliming created
    Support Team

    We should check why the event of deleting the entity is not triggered.

    This is a feature of ef. The solution is to use the code in issue or upgrade to ef core 3.0+

    https://github.com/dotnet/efcore/issues/10093

    I will investigate what the abp framework can do.