Base solution for your next web application
Open Closed

How to restrict users to only update their own entities... #3407


User avatar
0
joemo created

How do a restrict a logged in/authenticated user from making changes to entities they didn't create?

For example, if I have a CustomerAddress entity and repository. And I have an app service method UpdateCustomerAddress , and pass an address id to update, plus the fields to update. How do I restrict that method so that only the CreatorUser of the CustomerAddress can update it? Yes I could use abpsession to pass the user id as well, but that could be compromised in the javascript API calls.

I could create a permission "can update address", but still would need a way to verify that this is their address. Is there a way to find out who called a method?

Help appreciated!


2 Answer(s)
  • User Avatar
    0
    fengol created

    Create an empty interface for your domain entities to inherit. Then create an extension method and overload the Update to take the entity and a user Id (which you pass from AbpSession or whatever). The method must check if the entity implements your interface, then check if the passed user is the entity's creator before updating otherwise it just updates the entity as normal. You must decide what to do if the user is not the owner; in my example below I just throw an exception.

    <ins>You must just remember to use the new Update method everywhere instead of the normal update.</ins>

    Example below:

    The interface

    public interface IMustOwnEntity
    {
    }
    

    Extension Class

    public static class RepositoryExtensions
    {
        public static TEntity Update<TEntity>(this IRepository<TEntity> repository, TEntity entity, long userId) where TEntity : class, IEntity<int>, ICreationAudited
        {
            if (entity is IMustOwnEntity)
            {
                var exists = repository.FirstOrDefaultAsync((record) => record.Id == entity.Id && record.CreatorUserId == userId);
    
                if (exists != null)
                {
                    return repository.Update(entity);
                }
                else
                {
                    throw new Exception("Record does not belong to user");
                }
            }
            else
            {
                return repository.Update(entity);
            }
        }
    }
    

    P.S. The extension method will only be available on repositories where the entity implements ICreationAudited, IAudited, or IFullAudited so that there's a CreatorUserId to test against.

  • User Avatar
    0
    fengol created

    Maybe a simpler test. If your application service implements the project's AppServiceBase then it inherits a function called GetCurrentUserAsync which returns the calling user.

    Even simpler; ApplicationService contains an object called AbpSession with the calling user's Id.