- ABP Framework version: v6.0
- UI type: Angular
- DB provider: EF Core
- Tiered (MVC) or Identity Server Separated (Angular): MVC
- Exception message and stack trace:
- Steps to reproduce the issue:"
Usign OpenIdDict
I try to utilize the impersonate({ tenantId, userId }) function in ImpersonationService through Angular in Abp Commercial, but whenever I use it I get the following stack trace in my log:
The event OpenIddict.Validation.OpenIddictValidationEvents+ProcessAuthenticationContext was marked as rejected by OpenIddict.Validation.OpenIddictValidationHandlers+ValidateToken.
The impersonateTenant and impersonateUser in ImpersonationService are both working, but I need to be able to impersonate a tenant user from the host.
4 Answer(s)
-
0
but I need to be able to impersonate a tenant user from the host.
This is not supported by default, can you share your code?
-
0
So the function impersonate in ImpersonationService that have tenantid and userid as parameters - this does not work?
I knew how to do this in Identity Server - but have no reference for Openiddict - do have no code for now! Just trying to use the impersonate function. And I can see that the call is made and that the payload is correct when looking at ImpersonateUser or ImpersonateTenant. But the server code somehow does not work correctly.
-
0
hi
Please share the full logs and access_token
-
1
I have now solved this by doing an override of the existing functionality. Providing code here for others reference:
- Create ExtendedImpersonationExtensionGrant.cs in HttpApi.Host
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using System; using System.Security.Claims; using System.Threading.Tasks; using Volo.Abp.Account.Web.ExtensionGrants; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.MultiTenancy; using Volo.Abp.OpenIddict.ExtensionGrantTypes; namespace xxx.xxxxxx { public class ExtendedImpersonationExtensionGrant : ImpersonationExtensionGrant { protected IDataFilter _dataFilter { get; set; } public override Task<IActionResult> HandleAsync(ExtensionGrantContext context) { _dataFilter = ServiceProviderServiceExtensions.GetRequiredService<IDataFilter>(context.HttpContext.RequestServices); return base.HandleAsync(context); } protected async override Task<IActionResult> ImpersonateUserAsync(ExtensionGrantContext context, ClaimsPrincipal principal, Guid? tenantId, Guid userId) { if (!tenantId.HasValue && !this.currentTenant.IsAvailable) { IdentityUser foundUser = null; using (_dataFilter.Disable<IMultiTenant>()) { // host user foundUser = await this.userManager.FindByIdAsync(userId.ToString()); } if (foundUser != null) // impersonate directly into user in tenant! { return await base.ImpersonateUserAsync(context, principal, foundUser.TenantId, foundUser.Id); } } return await base.ImpersonateUserAsync(context, principal, tenantId, userId); } protected async override Task<IActionResult> BackToImpersonatorAsync(ExtensionGrantContext context, ClaimsPrincipal principal, Guid? tenantId, Guid userId) { IdentityUser foundUser = null; using (_dataFilter.Disable<IMultiTenant>()) { // host user foundUser = await this.userManager.FindByIdAsync(userId.ToString()); } if (foundUser != null && !foundUser.TenantId.HasValue) // Possible to revert back to host user { return await base.BackToImpersonatorAsync(context, principal, foundUser.TenantId, foundUser.Id); } return await base.BackToImpersonatorAsync(context, principal, tenantId, userId); } } }
- in HttpApi.HostModule.cs under ConfigureServices(ServiceConfigurationContext context) function add the following:
this.Configure<AbpOpenIddictExtensionGrantsOptions>((Action<AbpOpenIddictExtensionGrantsOptions>)(options => { options.Grants.Remove("Impersonation"); options.Grants.Add("Impersonation", (IExtensionGrant)new ExtendedImpersonationExtensionGrant()); }));
Then it works calling the following in Angular - and you can log in to a user under a tenent directly from a host and back again using standard functions:
this.impersonationService.impersonateUser(entity.id).subscribe((result) => { this.toaster.success('::Logged in - please wait'); })