From a1ca5979f87d725a820f97f2a6b2dd76f440ad31 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 13 Jul 2020 17:57:35 +0800 Subject: [PATCH] Cache the AccessToken in IdentityModelAuthenticationService. Resolve #4603 --- .../Volo.Abp.IdentityModel.csproj | 1 + .../IdentityModel/AbpIdentityModelModule.cs | 4 +- .../IdentityModelAuthenticationService.cs | 45 ++++++++++++++----- .../IdentityModelTokenCacheItem.cs | 29 ++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs diff --git a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj index 0143db8265..1fb77b36d9 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj +++ b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj @@ -17,6 +17,7 @@ + diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs index 7ab97c49fe..bf499e7b5f 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Caching; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; @@ -7,7 +8,8 @@ namespace Volo.Abp.IdentityModel { [DependsOn( typeof(AbpThreadingModule), - typeof(AbpMultiTenancyModule) + typeof(AbpMultiTenancyModule), + typeof(AbpCachingModule) )] public class AbpIdentityModelModule : AbpModule { diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs index 5e8c67a9ab..c20d473f81 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs +++ b/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.Headers; using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; @@ -26,18 +28,21 @@ namespace Volo.Abp.IdentityModel protected IHttpClientFactory HttpClientFactory { get; } protected ICurrentTenant CurrentTenant { get; } protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; } + protected IDistributedCache Cache { get; } public IdentityModelAuthenticationService( IOptions options, ICancellationTokenProvider cancellationTokenProvider, IHttpClientFactory httpClientFactory, ICurrentTenant currentTenant, - IOptions identityModelHttpRequestMessageOptions) + IOptions identityModelHttpRequestMessageOptions, + IDistributedCache cache) { ClientOptions = options.Value; CancellationTokenProvider = cancellationTokenProvider; HttpClientFactory = httpClientFactory; CurrentTenant = currentTenant; + Cache = cache; IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value; Logger = NullLogger.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}"); } - var tokenResponse = await GetTokenResponse(discoveryResponse, configuration); - - if (tokenResponse.IsError) + var cacheKey = CalculateCacheKey(discoveryResponse, configuration); + var tokenCacheItem = await Cache.GetAsync(cacheKey); + 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[] { "" }, StringSplitOptions.RemoveEmptyEntries); + throw new AbpException(withoutInnerException[0]); } - var rawError = tokenResponse.Raw; - var withoutInnerException = rawError.Split(new string[] { "" }, StringSplitOptions.RemoveEmptyEntries); - throw new AbpException(withoutInnerException[0]); + await Cache.SetAsync(cacheKey, new IdentityModelTokenCacheItem(tokenResponse.AccessToken), + new DistributedCacheEntryOptions() + { + //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) @@ -209,5 +229,10 @@ namespace Volo.Abp.IdentityModel client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); } } + + protected virtual string CalculateCacheKey(DiscoveryDocumentResponse discoveryResponse, IdentityClientConfiguration configuration) + { + return IdentityModelTokenCacheItem.CalculateCacheKey(discoveryResponse, configuration); + } } } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs new file mode 100644 index 0000000000..8d01b83c32 --- /dev/null +++ b/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)); + } + } +}