Base solution for your next web application
Open Closed

AbpSession.ToUserIdentifier() vs UserManager.FindByIdAsync #6760


User avatar
0
antonis created

What is the difference between the AbpSession.ToUserIdentifier() vs UserManager.FindByIdAsync? Which one is best to use?

Thanks in advance

Markdown is supported
Copy & paste or drag & drop images (max 30 MB per image)

27 Answer(s)
  • User Avatar
    0
    aaron created
    Support Team

    They serve very different purposes.

    AbpSession.ToUserIdentifier() gets an instance of UserIdentifier based solely on the values in the claims.

    UserManager.FindByIdAsync(...) gets a tracked instance of User from the database.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    maliming created
    Support Team

    They return different return values and are also used for different functions.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    Does UserManager hits database all the time or it caches results on memory?

    Thanks

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    maliming created
    Support Team

    Default will not be cached. Of course, it depends on the specific ORM. If you feel that there is a performance issue, you can implement the caching feature yourself.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    It gets a tracked instance from the database, so it hits the database.

    Entity instances are not (and probably should not be) cached directly.

    By the way, ASP<span></span>.NET Boilerplate is open source: https://github.com/aspnetboilerplate/aspnetboilerplate

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    I have a table X which references Tenant Table (each row has a TenantId)

    I want to get contents of table that belong to Tenant that requested X table.

    Which is best to use in terms of security

    AbpSession.ToUserIdentifier() or UserManager.FindByIdAsync(...)

    Thanks

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    maliming created
    Support Team

    You can use Repositories https://aspnetboilerplate.com/Pages/Documents/Repositories

    If you are not familiar with ABP and abp zero,The documentation will be your best tool. https://aspnetboilerplate.com/Pages/Documents/ http://docs.aspnetzero.com

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    Yes I know how to retrieve it.

    What I am asking is when I do a where x.TenantId = tenantId; What shall I use the AbpSession.ToUserIdentifier().TenantId or the UserManager.FindByIdAsync(...).TenantId as tenantId.

    In terms of security what is the correct approach?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    TenantId of user should not change.

    Also, ABP has built-in tenant data filters: https://aspnetboilerplate.com/Pages/Documents/Data-Filters#imusthavetenant

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    AbpSession.TenantId can be trusted.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    AbpSession.TenantId cannot be tampered or changed by the ?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    ASP<span></span>.NET Core provides cookie middleware which serializes a user principal into an encrypted cookie and then, on subsequent requests, validates the cookie, recreates the principal and assigns it to the User property on HttpContext.

    References:

    • https://aspnetcore.readthedocs.io/en/stable/security/authentication/cookie.html
    • https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-2.2
    • https://andrewlock.net/exploring-the-cookieauthenticationmiddleware-in-asp-net-core/
    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    Thanks @aaron for your help. Have checked the IMayHaveTenant documentation.

    I have one last question to that.

    How does this affect performance? To use a filter it means whenever i request something from database using IRepository it intercepts request and adds TenantId. IMHO this results in performance penalty opposed to do it manually when requesting it (x.TenantId = user.TenantId)

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    No significant impact on performance. Linq queries are compiled and cached by EF Core.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    I am not saying about the query execution. I was talking about how it intercepts and modify query when IMustHaveTenant is there.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    Okay.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    aaron I still dont understand how IMustHaveTenant works. Tried to read the documentation but it does not say much apart from IMustHaveTenant defines the TenantId property to distinguish between different tenant entities. ASP.NET Boilerplate uses the IAbpSession to get the current TenantId by default and automatically filters the query for the current tenant. How does it work with Update and Insert methods. Cant find any example. Do I need to set TenantId when updating or inserting or IMustHaveTenant does it automatically? Also If I set it manually does IMustHaveTenant checks if that TenantId is the correct one when updating a record?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    Do I need to set TenantId when updating or inserting or IMustHaveTenant does it automatically?

    ABP sets TenantId for IMustHaveTenant but not for IMayHaveTenant.

    Also If I set it manually does IMustHaveTenant checks if that TenantId is the correct one when updating a record?

    No, ABP does not check since it may be intended.

    The documentation describes the behaviour. If you want to know every detail about how it is implemented, then you can read the source code. Both ABP and EF Core are open source.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    ABP sets TenantId for IMustHaveTenant but not for IMayHaveTenant.

    I tried using IMustHaveTenant when calling Update method of the repository it and it does not set it. It actually throws an exception because value is 0.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    Show the error message and stack trace.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    This is my code:

    [Table("TestOrder")]
    public class Order : Entity<long>, IMustHaveTenant
    {
        [Required]        
        public string Name { get; set; }
    
        public string Description { get; set; }
    
        .....
    
        [ForeignKey("TenantId")]
        public Tenant Tenant { get; set; }
        public int TenantId { get; set; }
    }
        
    [HttpPost]
    [AbpAuthorize(AppPermissions.Pages_Orders_Edit)]
    public async Task UpdateOrder(OrderInputDto input)
    {
    	Order order = ObjectMapper.Map<Order>(input);
    
    	await ordersTypeRepository.UpdateAsync(order);
    }
    
    

    and this is the error that I get:

    An error occurred while updating the entries. See the inner exception for details.
    Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> MySql.Data.MySqlClient.MySqlException: Cannot add or update a child row: a foreign key constraint fails (`testfb`.`Order`, CONSTRAINT `FK_Order_AbpTenants_TenantId` FOREIGN KEY (`TenantId`) REFERENCES `AbpTenants` (`Id`) ON DELETE CASCADE) ---> MySql.Data.MySqlClient.MySqlException: Cannot add or update a child row: a foreign key constraint fails (`testfb`.`Order`, CONSTRAINT `FK_Order_AbpTenants_TenantId` FOREIGN KEY (`TenantId`) REFERENCES `AbpTenants` (`Id`) ON DELETE CASCADE)
       at MySqlConnector.Core.ServerSession.TryAsyncContinuation(Task`1 task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 1245
       at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
    --- End of stack trace from previous location where exception was thrown ---
       at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ResultSet.cs:line 42
       --- End of inner exception stack trace ---
       at MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet(ResultSet resultSet) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 74
       at MySql.Data.MySqlClient.MySqlDataReader.ReadFirstResultSetAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 299
       at MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(MySqlCommand command, CommandBehavior behavior, ResultSetProtocol resultSetProtocol, IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 284
       at MySqlConnector.Core.TextCommandExecutor.ExecuteReaderAsync(String commandText, MySqlParameterCollection parameterCollection, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\TextCommandExecutor.cs:line 37
       at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
       --- End of inner exception stack trace ---
       at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext _, ValueTuple`2 parameters, CancellationToken cancellationToken)
       at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList`1 entriesToSave, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
       at Abp.EntityFrameworkCore.AbpDbContext.SaveChangesAsync(CancellationToken cancellationToken) in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\AbpDbContext.cs:line 215
       at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext`3.SaveChangesAsync(CancellationToken cancellationToken) in D:\Github\aspnetboilerplate\src\Abp.ZeroCore.EntityFrameworkCore\Zero\EntityFrameworkCore\AbpZeroCommonDbContext.cs:line 165
       at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesInDbContextAsync(DbContext dbContext) in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 167
       at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesAsync() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 68
       at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.CompleteUowAsync() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 83
       at Abp.Domain.Uow.UnitOfWorkBase.CompleteAsync() in D:\Github\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkBase.cs:line 273
       at Abp.AspNetCore.Mvc.Uow.AbpUowActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) in D:\Github\aspnetboilerplate\src\Abp.AspNetCore\AspNetCore\Mvc\Uow\AbpUowActionFilter.cs:line 49
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
       at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
    
    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    Are you logged in as tenant? What is the value of AbpSession.TenantId?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    Yes I am logged in. I found out what is the problem. IMustHaveTenant does not work for db Update operations. only for create, read and delete.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    aaron created
    Support Team

    Yes, ABP only sets TenantId for IMustHaveTenant added entities by design. If you set it to 0 and update it, then ABP doesn't stop you.

    Yes, ABP has built-in tenant data filters for read.

    What do you mean by "work for ... delete"?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    antonis created

    When someone call repository<TEntity>.Delete(id) where TEntity implements IMustHaveTenant it cannot delete that TEntity if it does not belong to him

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)