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)
-
0
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.
-
0
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.