Yes, but I'm not sure whether I am doing it right. Here is the code I am using for this just before calling tokenAuthClient.ImpersonatedAuthenticateAsync
(and still getting the same error as mentioned above):
_httpClient.DefaultRequestHeaders.Remove("Abp.TenantId");
_httpClient.DefaultRequestHeaders.Add("Abp.TenantId",selectedTenantId.ToString());
I have also tried to modify the header for the HttpRequestMessage inside the generated client as follows,with the same outcome:
request_.Headers.Remove("Abp.TenantId");
request_.Headers.Add("Abp.TenantId", selectedTenantId?.ToString());
@ryancyq The provided link gives a 404 error
I am writing a utility that allows a host user to do batch loading of data on behalf of a tenant, via our API. For this, I have generated a .Net Core 2.2 client with NSwag, based on the generated swagger docs. This of course means that we use TokenAuth for authentication.
I am getting stuck with impersonation though. I am able to get an impersonation token, but get stuck when I want to authenticate as the impersonated user & tenant.
Here is my code through which I invoke the generated TokenAuth client:
// Get the impersonation token...
var accountClient = new AccountClient(_baseUri, _httpClient);
var impersonationToken = (await accountClient.ImpersonateAsync(new ImpersonateInput
{
TenantId = selectedTenantId,
UserId = selectedUserId,
})).ImpersonationToken;
var tokenAuthClient = new TokenAuthClient(_baseUri, _httpClient);
var impersonatedAccessToken =
(await tokenAuthClient.ImpersonatedAuthenticateAsync(impersonationToken)).AccessToken; // <== This call is generating Http Error 500
In my Web.Core
project, the ImpersonatedAuthenticate
method is being called on TokenAuthController
as follows:
[HttpPost]
public async Task<ImpersonatedAuthenticateResultModel> ImpersonatedAuthenticate(string impersonationToken)
{
var result = await _impersonationManager.GetImpersonatedUserAndIdentity(impersonationToken); <== This line is generating the exception
var accessToken = CreateAccessToken(await CreateJwtClaims(result.Identity, result.User));
return new ImpersonatedAuthenticateResultModel
{
AccessToken = accessToken,
EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds
};
}
Here is the exception I am getting:
Further details:
Swashbuckle depends on ApiExplorer, and the use of the ApiExplorer attribute limits us to specifying only a single groupname per controller / action. As per @ryancyq above, "service proxies are generated via NSwag for angular project." and it seems that during this process a dependency is broken.
The workaround was to create my own attribute for delimiting one-or-more groupnames for an appservice controller or action, and subsequently use reflection in my DocInclusionPredicateFunction
to retrieve the groupnames for an action or its containing controller.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class SwaggerDocAttribute: Attribute
{
public SwaggerDocAttribute(params string[] includeInDocuments)
{
IncludeInDocuments = includeInDocuments;
}
public string[] IncludeInDocuments { get; }
}
options.DocInclusionPredicate((docName, apiDesc) =>
{
if (!apiDesc.ActionDescriptor.IsControllerAction())
{
return false;
}
apiDesc.TryGetMethodInfo(out MethodInfo methodInfo);
var actionDocs = methodInfo.GetCustomAttributes<SwaggerDocAttribute>()
.SelectMany(a => a.IncludeInDocuments);
var controllerDocs = methodInfo.DeclaringType.GetCustomAttributes<SwaggerDocAttribute>()
.SelectMany(a => a.IncludeInDocuments);
switch (docName)
{
case "HostApiv1":
return apiDesc.GroupName == null ||
actionDocs.Contains("HostApiv1") ||
controllerDocs.Contains("HostApiv1");
case "TenantApiv1":
return apiDesc.GroupName == null ||
actionDocs.Contains("TenantApiv1") ||
controllerDocs.Contains("TenantApiv1");
default:
return true;
}
});
Usage
[DisableAuditing]
[AbpAuthorize(AppPermissions.HostSpecific.Dashboard.Access)]
//[ApiExplorerSettings(GroupName = "HostApiv1")]
[SwaggerDoc("HostApiv1")]
public class HostDashboardAppService : ZenDetectAppServiceBase, IHostDashboardAppService
{
//...
}
@ryancyq @ismcagdas That works insofar my swagger documentation is concerned, however, it now seems that whenever an app service is decorated with either [ApiExplorerSettings(GroupName = "HostApiv1")]
or [ApiExplorerSettings(GroupName = "TenantApiv1")]
, my client side dependencies on those services are broken. It seems that somehow AbpServiceProxies has a dependency on Swagger generation?
I have created two OpenApi specifications (HostApiv1
and TenantApiv1
) as follows in Startup.cs:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("HostApiv1", new Info { Title = "Host API v1", Version = "v1" });
options.SwaggerDoc("TenantApiv1", new Info { Title = "Tenant API v1", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.IgnoreObsoleteActions();
options.IgnoreObsoleteProperties();
options.OrderActionsBy((apiDesc) => $"{apiDesc.RelativePath}");
options.DescribeAllEnumsAsStrings();
});
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint(_appConfiguration["App:HostApiSwaggerEndPoint"], "Host API v1");
options.SwaggerEndpoint(_appConfiguration["App:TenantApiSwaggerEndPoint"], "Tenant API v1");
//...
});
However, when I decorate my AppService classes with [ApiExplorerSettings(GroupName = "HostApiv1")]
, the grouping is ignored and the tag (AppService controller), along with all of its operations (actions / methods), still appear under both documents.
Please advise.
Hi @ismcagdas
No. I had to use workarounds.
@alper
Yes, that's a typo. It should be (and is) ITransientDependency
.
OK, interesting....
[UnitOfWork(IsDisabled = true)]
throws the original exceptionWhy would the IUnitOfWork not resolve for the BackgroundJob<TArgs>
base class? How do I go about fixing it?
Hi @alper
Thanks for the assistance. I have tried both ways, unsuccesfully unfortunately.
However, when I did this...
[UnitOfWork]
public override void Execute(TroubleshootingBackgroundJobArgs args)
{
using(var uow = UnitOfWorkManager.Begin()) // <== Exception generated here...
{
repository.GetAll().ToList();
uow.Complete();
}
}
.... I got the following exception:
Abp.AbpException HResult=0x80131500 Message=Must set UnitOfWorkManager before use it. Source=Abp StackTrace: at Abp.BackgroundJobs.BackgroundJob
1.get_UnitOfWorkManager() at Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList.Infrastructure.Persons.PersonMonitoringBatch.PersonMonitoringBatchSearchJob.ExecuteJob(PersonMonitoringBatchSearhJobArgs args) in D:\Projects\ZenDetect\Modules\Sanctions\Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList\Infrastructure\Persons\PersonMonitoringBatch\PersonMonitoringBatchSearchJob.cs:line 54 at Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList.Core.BatchSearchJobBase
1.Execute(TBatchSearhJobArgs args) in D:\Projects\ZenDetect\Modules\Sanctions\Sanctions.SearchServices.Infrastructure.UnscConsolidatedSanctionList\Core\BatchSearchJobBase.cs:line 20
Seems like the Unit of Work object is not resolving, for some reason?