Open Closed

Hide or protect admin user #7896


User avatar
0
ageiter created
  • ABP Framework version: v8.2.2
  • UI Type: Blazor Server
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no

Scenario: In our web application, our customers get one tenant each. The customer then has the option to add further users to the tenant (other employees of the company). To be able to create (and delete) other users, they need permission for user management (Create, Edit, Delete, View details). We do not want to give them any other rights (no role management, no sessions, ...).

So that we still have an admin user (for us) who has all the admin rights, we would like to preserve the general admin user. However, the customer does not receive this login data. We do not want the customer to be able to change / delete this user.

Is this procedure unusual? What are best practices for this case, which certainly occurs often?

  1. Because the user has rights to the user management, he can delete or change our admin user. Of course, it would be best if he could not even see this user. Otherwise, however, the admin user would have to be protected against deletion/modification. What is the best way to protect or hide it?
  2. Would there be a way that the host admin user could log in to all tenants and have admin rights? Or does that make no sense / is impossible? Then you could remove the admin user from the tenant.

Menu item: I would also like the customer not to see the Identity management menu item, but directly an item named User management. How should I do this?

I have noticed something else: User has permission to edit a user. Now the item “Sessions” appears in the action menu. If I want to open this, the error message Volo.Abp.Authorization.AbpAuthorizationException appears (because the user has not set the “Sessions” permission). This should then also not be available in the menu.

Thanks, Adrian


22 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Because the user has rights to the user management, he can delete or change our admin user. Of course, it would be best if he could not even see this user. Otherwise, however, the admin user would have to be protected against deletion/modification. What is the best way to protect or hide it?

    you can override the IdentityUserAppService to hide admin from return. and override the update/delete method.

    Would there be a way that the host admin user could log in to all tenants and have admin rights? Or does that make no sense / is impossible? Then you could remove the admin user from the tenant.

    You can use the tenant simulation feature

    I would also like the customer not to see the Identity management menu item, but directly an item named User management. How should I do this?

    you can add a new MainMenuContributor to change the menu name.

    for example:

    if(currentUser.name != "admin")
    {
        var administrationMenu = context.Menu.GetAdministration();
        administrationMenu.TryRemoveMenuItem("AbpIdentity");
        administrationMenu.AddItem(new ApplicationMenuItem(IdentityProMenus.Users, new FixedLocalizableString("User management"), url: "~/identity/users").RequirePermissions(IdentityPermissions.Users.Default));
    }
     
    
  • User Avatar
    0
    ageiter created

    Hi liangshiwei, thank you for your answers.

    You can use the tenant simulation feature

    What do you mean by “tenant simulation”? I assume you mean the “Login with this tenant” button. But this only works if an admin user is assigned to the tenant. However, I mean the option of being able to log in to the tenants with the host admin and having admin rights.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    What do you mean by “tenant simulation”? I assume you mean the “Login with this tenant” button. But this only works if an admin user is assigned to the tenant. However, I mean the option of being able to log in to the tenants with the host admin and having admin rights

    actually, this is impossible. Because tenants and host data are independent

  • User Avatar
    0
    ageiter created

    actually, this is impossible. Because tenants and host data are independent

    Ok, that's what I assumed.

    Did you see that I found a bug? Please enter this as a bug in your backlog.

    User has permission to edit a user. Now the item “Sessions” appears in the action menu. If I want to open this, the error message Volo.Abp.Authorization.AbpAuthorizationException appears (because the user has not set the “Sessions” permission). This should then also not be available in the menu.

    I would also like to know what you would suggest as best practice for such a scenario as I have described?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    can you share the full error logs?

    I will check it.

    I would also like to know what you would suggest as best practice for such a scenario as I have described?

    As I said before, you can hide the admin account.

  • User Avatar
    0
    ageiter created

    As I said before, you can hide the admin account.

    Ok, I just wanted to make sure whether you would recommend this as best practice.

    can you share the full error logs?

    This is easy to reproduce: Revoke a user's rights to the sessions. But he still has the rights for user management. Then click in actions menu to the item "Sessions". Popup opens, but the data cannot be loaded due to missing authorizations. Because the error is not caught, the popup cannot be closed and the page must be reloaded.

    2024-09-16 13:10:39.952 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Sessions
    2024-09-16 13:10:40.282 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Users.Import
    2024-09-16 13:10:40.293 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Users.Export
    2024-09-16 13:10:40.337 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Sessions
    2024-09-16 13:10:40.947 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Users.Import
    2024-09-16 13:10:40.951 +02:00 [INF] Authorization failed. These requirements were not met:
    PermissionRequirement: AbpIdentity.Users.Export
    2024-09-16 13:10:41.085 +02:00 [WRN] Unhandled exception rendering component: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.
    Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.
       at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, AuthorizationPolicy policy)
       at Volo.Abp.Authorization.MethodInvocationAuthorizationService.CheckAsync(MethodInvocationAuthorizationContext context)
       at Volo.Abp.Authorization.AuthorizationInterceptor.AuthorizeAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Volo.Abp.Identity.Pro.Blazor.Pages.Identity.UserManagement.GetSessionsAsync()
       at Volo.Abp.Identity.Pro.Blazor.Pages.Identity.UserManagement.OnSessionsDataGridReadAsync(DataGridReadDataEventArgs`1 e)
       at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
       at Blazorise.DataGrid.DataGrid`1.HandleReadData(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.HandleReadData(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.ReloadInternal(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.Reload(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.OnAfterRenderAsync(Boolean firstRender)
       at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
    2024-09-16 13:10:41.106 +02:00 [ERR] Unhandled exception in circuit 'N2gQs-_B3hRk7fLkFUyHWOQEsrMSLn2jdUNcr6S9ck8'.
    Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.
       at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, AuthorizationPolicy policy)
       at Volo.Abp.Authorization.MethodInvocationAuthorizationService.CheckAsync(MethodInvocationAuthorizationContext context)
       at Volo.Abp.Authorization.AuthorizationInterceptor.AuthorizeAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Volo.Abp.Identity.Pro.Blazor.Pages.Identity.UserManagement.GetSessionsAsync()
       at Volo.Abp.Identity.Pro.Blazor.Pages.Identity.UserManagement.OnSessionsDataGridReadAsync(DataGridReadDataEventArgs`1 e)
       at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
       at Blazorise.DataGrid.DataGrid`1.HandleReadData(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.HandleReadData(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.ReloadInternal(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.Reload(CancellationToken cancellationToken)
       at Blazorise.DataGrid.DataGrid`1.OnAfterRenderAsync(Boolean firstRender)
       at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
    
    
  • User Avatar
    0
    ageiter created

    The admin user is automatically created when the new tenant is created. With the customer's e-mail address and password.

    However, I would now like two users to be created. On the one hand the user for the customer (with the entered mail address as username) and on the other hand the admin user for us as host.

    I have already extended the TenantAppService (of Volo.Saas.Host namespace) & TenantDataSeeder. Where would be the right point to realize this?

    Is it best to write the CreateAsync method completely by myself? I would prefer to continue using base.CreateAsync() and add the other one afterwards.

  • User Avatar
    0
    ageiter created

    This is currently my code. But when creating the customer user, it ends in an exception.

        public override async Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
        {
            // Set initial edition
            if (input.EditionId == null)
            {
                input.EditionId = (await _editionRepository.FindByDisplayNameAsync(PalmaConsts.EditionNameInitial)).Id;
            }
    
            // Get email & password for customer user (which is created later)
            var customerEmail = input.AdminEmailAddress;
            var customerPassword = input.AdminPassword;
    
            // Set default email & password for admin user to input
            input.AdminEmailAddress = PalmaConsts.AdminEmailDefaultValue;
            input.AdminPassword = PalmaConsts.AdminPasswordDefaultValue;
    
            // Create tenant (with default admin user)
            var tenant = await base.CreateAsync(input);
    
            // Create customer user
            using (CurrentTenant.Change(tenant.Id, tenant.Name))
            {
                var customerUser = await _userAppServce.CreateAsync(new IdentityUserCreateDto()
                {
                    UserName = customerEmail,
                    Email = customerEmail,
                    Password = customerPassword,
                    RoleNames = new[]
                    {
                        PalmaConsts.RoleNameCustomer
                    }
                });
            }
    
            // Seed initial data
            await SeedInitialDataAsync(tenant, input);
    
            return tenant;
        }
    

    AbpAuthorizationException:

    2024-09-16 16:26:12.176 +02:00 [WRN] Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.
    Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.
       at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, AuthorizationPolicy policy)
       at Volo.Abp.Authorization.MethodInvocationAuthorizationService.CheckAsync(MethodInvocationAuthorizationContext context)
       at Volo.Abp.Authorization.AuthorizationInterceptor.AuthorizeAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.ProcessWithNewAuditingScopeAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, ICurrentUser currentUser, IAuditingManager auditingManager, IAuditingHelper auditingHelper, IUnitOfWorkManager unitOfWorkManager)
       at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Palma.Saas.PalmaTenantAppService.CreateAsync(SaasTenantCreateDto input)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
       at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
       at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
       at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
       at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
       at Volo.Abp.BlazoriseUI.AbpCrudPageBase`10.CreateEntityAsync()
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    This is easy to reproduce: Revoke a user's rights to the sessions. But he still has the rights for user management. Then click in actions menu to the item "Sessions". Popup opens, but the data cannot be loaded due to missing authorizations. Because the error is not caught, the popup cannot be closed and the page must be reloaded.

    i could not reproduce the problem

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    The admin user is automatically created when the new tenant is created. With the customer's e-mail address and password.

    You don't need to extend TenantAppService, you can use data seeder.: https://abp.io/docs/latest/framework/infrastructure/data-seeding

  • User Avatar
    0
    ageiter created

    This is easy to reproduce: Revoke a user's rights to the sessions. But he still has the rights for user management. Then click in actions menu to the item "Sessions". Popup opens, but the data cannot be loaded due to missing authorizations. Because the error is not caught, the popup cannot be closed and the page must be reloaded.

    i could not reproduce the problem

    Ok... These are the permissions on the role:

    I am using version 8.2.2... maybe it's already fixed in 8.3?

  • User Avatar
    0
    ageiter created

    You don't need to extend TenantAppService, you can use data seeder.: https://abp.io/docs/latest/framework/infrastructure/data-seeding

    Thank you, that worked.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    I am using version 8.2.2... maybe it's already fixed in 8.3?

    maybe you can try

  • User Avatar
    0
    ageiter created

    I am using version 8.2.2... maybe it's already fixed in 8.3?

    maybe you can try

    It's not that important to me, I just wanted to make a contribution to improving ABP.

    My next problem: The tenant should be created automatically when a customer registers. Now, of course, I have a problem with the permissions, as certain rights are required to create a tenant and an anonymous user cannot have these.

    I have already extended the TenantAppService and the CreateAsync method, but the permissions are taken from the base class.

    How can I achieve my goal?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    HI,

    you can try this

    [Authorize]
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(ITenantAppService))]
    public class MyTenantAppService : TenantAppService
    {
        ....
        
        [AllowAnonymous]
        public override Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
        {
            //Manually check permissions here
            ...
        }
    }
    
    
  • User Avatar
    0
    ageiter created

    [AllowAnonymous] works, thank you for the hint.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    : )

  • User Avatar
    0
    ageiter created

    Another problem: After creating the tenant (TenantAppService.CreateAsync), I would like to change something about the user. But it seems that the user is not yet in the database. It is not (yet) found...

    Is the transaction only completed after all EventHandlers have been handled? Or is this a timing problem?

    public class TenantEventHandler : IDistributedEventHandler<TenantCreatedEto>, ITransientDependency
    {
        private readonly IdentityUserManager _userManager;
        private readonly ICurrentTenant _currentTenant;
    
        public TenantEventHandler(IdentityUserManager userManager, ICurrentTenant currentTenant)
        {
            _userManager = userManager;
            _currentTenant = currentTenant;
        }
    
        public async Task HandleEventAsync(TenantCreatedEto eventData)
        {
            using (_currentTenant.Change(eventData.Id))
            {
                // Set admin user as confirmed
                var adminUser = await _userManager.FindByEmailAsync(PalmaConsts.AdminEmailDefaultValue);
                if (adminUser != null)
                {
                    adminUser.SetEmailConfirmed(true);
                    await _userManager.UpdateAsync(adminUser);
                }
            }
        }
    
  • User Avatar
    0
    ageiter created

    Ok, I've seen the problem. It's because my TenantEventHandler was called first and then PalmaTenantDatabaseMigrationHandler, which creates the admin user.

    Probably you can't specify a order?

    I would simply prefer to have my logic in a separate EventHandler, as there are also further steps (sending mail etc.) which have nothing to do with database migration...

        public async Task HandleEventAsync(TenantCreatedEto eventData)
        {
            await MigrateAndSeedForTenantAsync(
                eventData.Id,
                eventData.Properties.GetOrDefault("AdminEmail") ?? PalmaConsts.AdminEmailDefaultValue,
                eventData.Properties.GetOrDefault("AdminPassword") ?? PalmaConsts.AdminPasswordDefaultValue
            );
    
            using (_currentTenant.Change(eventData.Id))
            {
                // Set admin user as confirmed
                var adminUser = await _userManager.FindByEmailAsync(PalmaConsts.AdminEmailDefaultValue);
                if (adminUser != null)
                {
                    adminUser.SetEmailConfirmed(true);
                    await _userManager.UpdateAsync(adminUser);
                }
            }
        }
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    You can publish an event in PalmaTenantDatabaseMigrationHandler

    public async Task HandleEventAsync(TenantCreatedEto eventData)
    {
        await MigrateAndSeedForTenantAsync(
            eventData.Id,
            eventData.Properties.GetOrDefault("AdminEmail") ?? "admin@abp.io",
            eventData.Properties.GetOrDefault("AdminPassword") ?? "1q2w3E*"
        );
        
        .....
        await eventBus.PublishAsync(new TenantSeededEto(...));
    }
    
    public class TenantEventHandler : IDistributedEventHandler<TenantSeededEto>, ITransientDependency
    {
        private readonly IdentityUserManager _userManager;
        private readonly ICurrentTenant _currentTenant;
    
        public TenantEventHandler(IdentityUserManager userManager, ICurrentTenant currentTenant)
        {
            _userManager = userManager;
            _currentTenant = currentTenant;
        }
    
        public async Task HandleEventAsync(TenantSeededEto eventData)
        {
            ....
        }
    
  • User Avatar
    0
    ageiter created

    You can publish an event in PalmaTenantDatabaseMigrationHandler

    Ah yes, that's it. Thank you!

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    : )

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11