- 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?
- 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?
- 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)
-
0
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 hideadmin
from return. and override theupdate/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)); }
-
0
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.
-
0
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
-
0
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?
-
0
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.
-
0
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)
-
0
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.
-
0
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()
-
0
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
-
0
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
-
0
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?
-
0
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.
-
0
I am using version 8.2.2... maybe it's already fixed in 8.3?
maybe you can try
-
0
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?
-
0
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 ... } }
-
0
[AllowAnonymous]
works, thank you for the hint. -
0
: )
-
0
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); } } }
-
0
Ok, I've seen the problem. It's because my
TenantEventHandler
was called first and thenPalmaTenantDatabaseMigrationHandler
, 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); } } }
-
0
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) { .... }
-
0
You can publish an event in
PalmaTenantDatabaseMigrationHandler
Ah yes, that's it. Thank you!
-
0
: )