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)
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?
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.
Ok, thank you for the answer.
I thought I would have to implement this myself. I just hoped you could give me a few tips on how to do it. Or perhaps how you implemented it at Abp.
Sorry for the three new questions to the payment / subscriptions:
Where do I configure whether a subscription is automatically renewed or whether the user has to renew it manually? You at ABP have implemented the “Automatic Renewal” option in “Organization Management”. How does it work if this is changed? Is there a request to the payment provider and then this is stored there with the subscription?
How can you implement that a customer can cancel their subscription again?
We still need the option for the customer to view the invoice. Stripe has a link for this, but how can I access this link? It would be best if this could be displayed directly on the Payment Success page.
Please send an email to liming.ma@volosoft.com I will share the source code.
Thanks a lot for your mail.
Enabling WebHooks Configuring Web Hooks is highly important for subscriptions otherwise your application won't be able to get subscription changes, such as canceled or updated states. Each gateway has its own configuration:
https://abp.io/docs/commercial/5.1/modules/payment#enabling-webhooks
Stripe will send a request to your website(
yourdomain.com/payment/stripe/webhook
)
Yes, exactly, I am aware of that. And it also works for renewing a subscription. But an early cancellation or change of the subscription duration is not implemented (I would have thought that this should come via the “customer.subscription.updated” event).
Ok, that's a good hint and could work like this.
Is there a way to get the source code of the StripePaymentGateway
or the PaymentModule in general?
We may still have to implement Payrexx as a gateway. And it is quite time-consuming and complex if the StripePaymentGateway
is a black box as a template.
In addition, we have identified a problem with the WebHooks in connection with subscriptions at Stripe and it is now difficult to say whether the problem is in the payment module or whether we have not understood the mechanism. An insight into the implementation of the distributed events would be helpful.
The problem identified is as follows: We cancel a subscription with Stripe before the end (e.g. with a refund to the customer), the payment module processes the event (I can see this in the log file), but the EditionEndDateUtc
field in the SaasTenant is not changed. Now we would like to know WHAT exactly the payment module processes when such an event occurs and what we have to do ourselves. We use the EditionEndDateUtc
to check whether the subscription is still valid and it still contains the previous date and not the updated one.
Can you share the screenshot of
list
page?I think you can only customize the
list
page to do this.
What do you mean by the List page? Which one?