Browse Source

Cache the AccessToken in IdentityModelAuthenticationService.

Resolve #4603
pull/4742/head
maliming 6 years ago
parent
commit
a1ca5979f8
  1. 1
      framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj
  2. 4
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs
  3. 45
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs
  4. 29
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs

1
framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj

@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityModel" Version="4.3.0" /> <PackageReference Include="IdentityModel" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.5" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> <ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" /> <ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup> </ItemGroup>

4
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -7,7 +8,8 @@ namespace Volo.Abp.IdentityModel
{ {
[DependsOn( [DependsOn(
typeof(AbpThreadingModule), typeof(AbpThreadingModule),
typeof(AbpMultiTenancyModule) typeof(AbpMultiTenancyModule),
typeof(AbpCachingModule)
)] )]
public class AbpIdentityModelModule : AbpModule public class AbpIdentityModelModule : AbpModule
{ {

45
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs

@ -10,6 +10,8 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -26,18 +28,21 @@ namespace Volo.Abp.IdentityModel
protected IHttpClientFactory HttpClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; }
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; } protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; }
protected IDistributedCache<IdentityModelTokenCacheItem> Cache { get; }
public IdentityModelAuthenticationService( public IdentityModelAuthenticationService(
IOptions<AbpIdentityClientOptions> options, IOptions<AbpIdentityClientOptions> options,
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions) IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions,
IDistributedCache<IdentityModelTokenCacheItem> cache)
{ {
ClientOptions = options.Value; ClientOptions = options.Value;
CancellationTokenProvider = cancellationTokenProvider; CancellationTokenProvider = cancellationTokenProvider;
HttpClientFactory = httpClientFactory; HttpClientFactory = httpClientFactory;
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
Cache = cache;
IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value; IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value;
Logger = NullLogger<IdentityModelAuthenticationService>.Instance; Logger = NullLogger<IdentityModelAuthenticationService>.Instance;
} }
@ -76,21 +81,36 @@ namespace Volo.Abp.IdentityModel
throw new AbpException($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}"); throw new AbpException($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}");
} }
var tokenResponse = await GetTokenResponse(discoveryResponse, configuration); var cacheKey = CalculateCacheKey(discoveryResponse, configuration);
var tokenCacheItem = await Cache.GetAsync(cacheKey);
if (tokenResponse.IsError) if (tokenCacheItem == null)
{ {
if (tokenResponse.ErrorDescription != null) var tokenResponse = await GetTokenResponse(discoveryResponse, configuration);
if (tokenResponse.IsError)
{ {
throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}"); if (tokenResponse.ErrorDescription != null)
{
throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. " +
$"Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}");
}
var rawError = tokenResponse.Raw;
var withoutInnerException = rawError.Split(new string[] { "<eof/>" }, StringSplitOptions.RemoveEmptyEntries);
throw new AbpException(withoutInnerException[0]);
} }
var rawError = tokenResponse.Raw; await Cache.SetAsync(cacheKey, new IdentityModelTokenCacheItem(tokenResponse.AccessToken),
var withoutInnerException = rawError.Split(new string[] { "<eof/>" }, StringSplitOptions.RemoveEmptyEntries); new DistributedCacheEntryOptions()
throw new AbpException(withoutInnerException[0]); {
//Subtract 10 seconds of network request time.
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(tokenResponse.ExpiresIn - 10)
});
return tokenResponse.AccessToken;
} }
return tokenResponse.AccessToken; return tokenCacheItem.AccessToken;
} }
protected virtual void SetAccessToken(HttpClient client, string accessToken) protected virtual void SetAccessToken(HttpClient client, string accessToken)
@ -209,5 +229,10 @@ namespace Volo.Abp.IdentityModel
client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
} }
} }
protected virtual string CalculateCacheKey(DiscoveryDocumentResponse discoveryResponse, IdentityClientConfiguration configuration)
{
return IdentityModelTokenCacheItem.CalculateCacheKey(discoveryResponse, configuration);
}
} }
} }

29
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs

@ -0,0 +1,29 @@
using System;
using System.Linq;
using IdentityModel.Client;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.IdentityModel
{
[Serializable]
[IgnoreMultiTenancy]
public class IdentityModelTokenCacheItem
{
public string AccessToken { get; set; }
public IdentityModelTokenCacheItem()
{
}
public IdentityModelTokenCacheItem(string accessToken)
{
AccessToken = accessToken;
}
public static string CalculateCacheKey(DiscoveryDocumentResponse discoveryResponse, IdentityClientConfiguration configuration)
{
return discoveryResponse.TokenEndpoint + string.Join(",", configuration.Select(x => x.Key + ":" + x.Value));
}
}
}
Loading…
Cancel
Save