6 changed files with 187 additions and 1 deletions
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
|||
<Version>3.0.0</Version> |
|||
<Authors>LINGYUN</Authors> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<OutputPath>D:\LocalNuget</OutputPath> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Caching" Version="3.0.0" /> |
|||
<PackageReference Include="Volo.Abp.IdentityModel" Version="3.0.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.IdentityModel; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Security; |
|||
|
|||
namespace LINGYUN.Abp.IdentityModel |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpIdentityModelModule), |
|||
typeof(AbpSecurityModule))] |
|||
public class AbpCachedIdentityModelModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.IdentityModel |
|||
{ |
|||
public class IdentityModelAuthenticationCacheItem |
|||
{ |
|||
public string AccessToken { get; set; } |
|||
public IdentityModelAuthenticationCacheItem() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public IdentityModelAuthenticationCacheItem(string accessToken) |
|||
{ |
|||
AccessToken = accessToken; |
|||
} |
|||
|
|||
public static string CalculateCacheKey(string grantType, string clientId, string userName = null) |
|||
{ |
|||
if (userName.IsNullOrWhiteSpace()) |
|||
{ |
|||
return "gt:" + grantType + ",ci:" + clientId; |
|||
} |
|||
return "gt:" + grantType + ",ci:" + clientId + ",un:" + userName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,107 @@ |
|||
using IdentityModel.Client; |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.IdentityModel; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Security.Encryption; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LINGYUN.Abp.IdentityModel |
|||
{ |
|||
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)] |
|||
[ExposeServices( |
|||
typeof(IIdentityModelAuthenticationService), |
|||
typeof(IdentityModelAuthenticationService))] |
|||
public class IdentityModelCachedAuthenticationService : IdentityModelAuthenticationService |
|||
{ |
|||
protected IStringEncryptionService EncryptionService { get; } |
|||
protected IDistributedCache<IdentityModelAuthenticationCacheItem> Cache { get; } |
|||
public IdentityModelCachedAuthenticationService( |
|||
IOptions<AbpIdentityClientOptions> options, |
|||
ICancellationTokenProvider cancellationTokenProvider, |
|||
IHttpClientFactory httpClientFactory, |
|||
ICurrentTenant currentTenant, |
|||
IStringEncryptionService encryptionService, |
|||
IDistributedCache<IdentityModelAuthenticationCacheItem> cache, |
|||
IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions) |
|||
: base(options, cancellationTokenProvider, httpClientFactory, currentTenant, identityModelHttpRequestMessageOptions) |
|||
{ |
|||
Cache = cache; |
|||
EncryptionService = encryptionService; |
|||
} |
|||
|
|||
public override async Task<string> GetAccessTokenAsync(IdentityClientConfiguration configuration) |
|||
{ |
|||
var accessTokenCacheItem = await GetCacheItemAsync(configuration); |
|||
// 需要解密
|
|||
return EncryptionService.Decrypt(accessTokenCacheItem.AccessToken); |
|||
} |
|||
|
|||
protected virtual async Task<IdentityModelAuthenticationCacheItem> GetCacheItemAsync(IdentityClientConfiguration configuration) |
|||
{ |
|||
var cacheKey = IdentityModelAuthenticationCacheItem.CalculateCacheKey(configuration.GrantType, configuration.ClientId, configuration.UserName); |
|||
|
|||
Logger.LogDebug($"IdentityModelCachedAuthenticationService.GetCacheItemAsync: {cacheKey}"); |
|||
|
|||
var cacheItem = await Cache.GetAsync(cacheKey); |
|||
|
|||
if (cacheItem != null) |
|||
{ |
|||
Logger.LogDebug($"Found in the cache: {cacheKey}"); |
|||
return cacheItem; |
|||
} |
|||
|
|||
Logger.LogDebug($"Not found in the cache: {cacheKey}"); |
|||
|
|||
var tokenResponse = await GetAccessTokenResponseAsync(configuration); |
|||
// 需要加密
|
|||
var accessToken = EncryptionService.Encrypt(tokenResponse.AccessToken); |
|||
cacheItem = new IdentityModelAuthenticationCacheItem(accessToken); |
|||
var cacheEntryOptions = new DistributedCacheEntryOptions |
|||
{ |
|||
// 缓存前两分钟过期
|
|||
AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(tokenResponse.ExpiresIn - 120) |
|||
}; |
|||
|
|||
Logger.LogDebug($"Setting the cache item: {cacheKey}"); |
|||
await Cache.SetAsync(cacheKey, cacheItem, cacheEntryOptions); |
|||
|
|||
Logger.LogDebug($"Finished setting the cache item: {cacheKey}"); |
|||
|
|||
return cacheItem; |
|||
} |
|||
|
|||
protected virtual async Task<TokenResponse> GetAccessTokenResponseAsync(IdentityClientConfiguration configuration) |
|||
{ |
|||
var discoveryResponse = await GetDiscoveryResponse(configuration); |
|||
if (discoveryResponse.IsError) |
|||
{ |
|||
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) |
|||
{ |
|||
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]); |
|||
} |
|||
|
|||
return tokenResponse; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
# LINGYUN.Abp.IdentityModel |
|||
|
|||
abp框架 **IIdentityModelAuthenticationService**接口缓存版本 |
|||
|
|||
因官方**Volo.Abp.IdentityModel**模块没有对接口授权缓存,每次内部调用都会请求IDS服务器,会加重IDS服务器压力, |
|||
创建使用缓存的接口实现 |
|||
|
|||
## 配置使用 |
|||
|
|||
模块按需引用,需要配置**Volo.Abp.IdentityModel**模块所需配置项 |
|||
|
|||
|
|||
```csharp |
|||
[DependsOn(typeof(AbpCachedIdentityModelModule))] |
|||
public class YouProjectModule : AbpModule |
|||
{ |
|||
// other |
|||
} |
|||
``` |
|||
Loading…
Reference in new issue