Browse Source

Merge pull request #18175 from abpframework/dynamic-claims-patch

Enhance dynamic claims system.
pull/18190/head
Halil İbrahim Kalkan 3 years ago
committed by GitHub
parent
commit
827f90ae08
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 36
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/Extensions/DependencyInjection/AbpJwtBearerExtensions.cs
  2. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
  3. 20
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
  4. 10
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs
  5. 75
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
  6. 13
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs
  7. 13
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  8. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
  9. 40
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
  10. 31
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs
  11. 5
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs
  12. 51
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorBase.cs
  13. 55
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorCacheBase.cs
  14. 8
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs
  15. 6
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor.cs
  16. 11
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs
  17. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs
  18. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs

36
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/Extensions/DependencyInjection/AbpJwtBearerExtensions.cs

@ -0,0 +1,36 @@
using System;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.Security.Claims;
namespace Microsoft.Extensions.DependencyInjection;
public static class AbpJwtBearerExtensions
{
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder)
=> builder.AddAbpJwtBearer(JwtBearerDefaults.AuthenticationScheme, _ => { });
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, Action<JwtBearerOptions> configureOptions)
=> builder.AddAbpJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions);
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
=> builder.AddAbpJwtBearer(authenticationScheme, "Bearer", configureOptions);
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<JwtBearerOptions> configureOptions)
{
builder.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
var jwtBearerOption = new JwtBearerOptions();
configureOptions?.Invoke(jwtBearerOption);
if (!jwtBearerOption.Authority.IsNullOrEmpty())
{
options.RemoteRefreshUrl = jwtBearerOption.Authority.RemovePostFix("/") + options.RemoteRefreshUrl;
}
});
return builder.AddJwtBearer(authenticationScheme, displayName, options =>
{
configureOptions?.Invoke(options);
});
}
}

2
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj

@ -18,10 +18,12 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Security\Volo.Abp.Security.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="IdentityModel" />
</ItemGroup>
</Project>

20
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs

@ -1,10 +1,24 @@
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Abp.Security;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer;
[DependsOn(typeof(AbpSecurityModule))]
[DependsOn(typeof(AbpSecurityModule), typeof(AbpCachingModule))]
public class AbpAspNetCoreAuthenticationJwtBearerModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClient();
context.Services.AddHttpContextAccessor();
var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions<AbpClaimsPrincipalFactoryOptions>();
if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
{
context.Services.AddTransient<WebRemoteDynamicClaimsPrincipalContributor>();
context.Services.AddTransient<WebRemoteDynamicClaimsPrincipalContributorCache>();
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs

@ -0,0 +1,10 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
[DisableConventionalRegistration]
public class WebRemoteDynamicClaimsPrincipalContributor : RemoteDynamicClaimsPrincipalContributorBase<WebRemoteDynamicClaimsPrincipalContributor, WebRemoteDynamicClaimsPrincipalContributorCache>
{
}

75
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs

@ -0,0 +1,75 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
public class WebRemoteDynamicClaimsPrincipalContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase<WebRemoteDynamicClaimsPrincipalContributorCache>
{
public const string HttpClientName = nameof(WebRemoteDynamicClaimsPrincipalContributorCache);
protected IDistributedCache<AbpDynamicClaimCacheItem> Cache { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IHttpContextAccessor HttpContextAccessor { get; }
protected IOptions<WebRemoteDynamicClaimsPrincipalContributorOptions> Options { get; }
public WebRemoteDynamicClaimsPrincipalContributorCache(
IDistributedCache<AbpDynamicClaimCacheItem> cache,
IHttpClientFactory httpClientFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IHttpContextAccessor httpContextAccessor,
IOptions<WebRemoteDynamicClaimsPrincipalContributorOptions> options)
: base(abpClaimsPrincipalFactoryOptions)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
HttpContextAccessor = httpContextAccessor;
Options = options;
}
protected async override Task<AbpDynamicClaimCacheItem?> GetCacheAsync(Guid userId, Guid? tenantId = null)
{
return await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
}
protected async override Task RefreshAsync(Guid userId, Guid? tenantId = null)
{
try
{
if (HttpContextAccessor.HttpContext == null)
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - HttpContext is null!");
}
var authenticateResult = await HttpContextAccessor.HttpContext.AuthenticateAsync(Options.Value.AuthenticationScheme);
if (!authenticateResult.Succeeded)
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - authentication failed!");
}
var accessToken = authenticateResult.Properties?.GetTokenValue("access_token");
if (accessToken.IsNullOrWhiteSpace())
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - access_token is null or empty!");
}
var client = HttpClientFactory.CreateClient(HttpClientName);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, AbpClaimsPrincipalFactoryOptions.Value.RemoteRefreshUrl);
requestMessage.SetBearerToken(accessToken);
var response = await client.SendAsync(requestMessage);
response.EnsureSuccessStatusCode();
}
catch (Exception e)
{
Logger.LogWarning(e, $"Failed to refresh remote claims for user: {userId}");
throw;
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
public class WebRemoteDynamicClaimsPrincipalContributorOptions
{
public string AuthenticationScheme { get; set; }
public WebRemoteDynamicClaimsPrincipalContributorOptions()
{
AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme;
}
}

13
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Microsoft.Extensions.DependencyInjection;
@ -24,6 +25,16 @@ public static class AbpOpenIdConnectExtensions
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OpenIdConnectOptions> configureOptions)
{
builder.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
var openIdConnectOptions = new OpenIdConnectOptions();
configureOptions?.Invoke(openIdConnectOptions);
if (!openIdConnectOptions.Authority.IsNullOrEmpty())
{
options.RemoteRefreshUrl = openIdConnectOptions.Authority.RemovePostFix("/") + options.RemoteRefreshUrl;
}
});
return builder.AddOpenIdConnect(authenticationScheme, displayName, options =>
{
options.ClaimActions.MapAbpClaimTypes();
@ -38,7 +49,7 @@ public static class AbpOpenIdConnectExtensions
};
options.AccessDeniedPath = "/";
options.Events.OnTokenValidated = async (context) =>
{
var client = context.HttpContext.RequestServices.GetRequiredService<IOpenIdLocalUserCreationClient>();

8
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs

@ -7,6 +7,7 @@ using Volo.Abp.Features;
using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Security.Claims;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.Client;
@ -40,5 +41,12 @@ public class AbpAspNetCoreMvcClientCommonModule : AbpModule
context.Services.AddTransient<AbpApplicationConfigurationClientProxy>();
context.Services.AddTransient<AbpTenantClientProxy>();
var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions<AbpClaimsPrincipalFactoryOptions>();
if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
{
context.Services.AddTransient<RemoteDynamicClaimsPrincipalContributor>();
context.Services.AddTransient<RemoteDynamicClaimsPrincipalContributorCache>();
}
}
}

40
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs

@ -1,44 +1,10 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class RemoteDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
[DisableConventionalRegistration]
public class RemoteDynamicClaimsPrincipalContributor : RemoteDynamicClaimsPrincipalContributorBase<RemoteDynamicClaimsPrincipalContributor, RemoteDynamicClaimsPrincipalContributorCache>
{
public async override Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
if (identity == null)
{
return;
}
var userId = identity.FindUserId();
if (userId == null)
{
return;
}
var dynamicClaimsCache = context.GetRequiredService<RemoteDynamicClaimsPrincipalContributorCache>();
AbpDynamicClaimCacheItem dynamicClaims;
try
{
dynamicClaims = await dynamicClaimsCache.GetAsync(userId.Value, identity.FindTenantId());
}
catch (Exception e)
{
// In case if failed refresh remote dynamic cache, We force to clear the claims principal.
context.ClaimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
var logger = context.GetRequiredService<ILogger<RemoteDynamicClaimsPrincipalContributor>>();
logger.LogWarning(e, $"Failed to refresh remote dynamic claims cache for user: {userId.Value}");
return;
}
await AddDynamicClaimsAsync(context, identity, dynamicClaims.Claims);
}
}

31
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs

@ -3,24 +3,20 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
public class RemoteDynamicClaimsPrincipalContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase<RemoteDynamicClaimsPrincipalContributorCache>
{
public const string HttpClientName = nameof(RemoteDynamicClaimsPrincipalContributorCache);
public ILogger<RemoteDynamicClaimsPrincipalContributorCache> Logger { get; set; }
protected IDistributedCache<AbpDynamicClaimCacheItem> Cache { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IOptions<AbpClaimsPrincipalFactoryOptions> AbpClaimsPrincipalFactoryOptions { get; }
protected IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
public RemoteDynamicClaimsPrincipalContributorCache(
@ -28,25 +24,20 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
IHttpClientFactory httpClientFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator)
: base(abpClaimsPrincipalFactoryOptions)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
HttpClientAuthenticator = httpClientAuthenticator;
Logger = NullLogger<RemoteDynamicClaimsPrincipalContributorCache>.Instance;
}
public virtual async Task<AbpDynamicClaimCacheItem> GetAsync(Guid userId, Guid? tenantId = null)
protected async override Task<AbpDynamicClaimCacheItem?> GetCacheAsync(Guid userId, Guid? tenantId = null)
{
Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
var dynamicClaims = await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
if (dynamicClaims != null && !dynamicClaims.Claims.IsNullOrEmpty())
{
return dynamicClaims;
}
return await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
}
Logger.LogDebug($"Refresh dynamic claims for user: {userId} from remote service.");
protected async override Task RefreshAsync(Guid userId, Guid? tenantId = null)
{
try
{
var client = HttpClientFactory.CreateClient(HttpClientName);
@ -60,13 +51,5 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
Logger.LogWarning(e, $"Failed to refresh remote claims for user: {userId}");
throw;
}
dynamicClaims = await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
if (dynamicClaims == null || dynamicClaims.Claims.IsNullOrEmpty())
{
throw new AbpException($"Failed to refresh remote claims for user: {userId}");
}
return dynamicClaims!;
}
}

5
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs

@ -12,11 +12,13 @@ public class AbpClaimsPrincipalFactoryOptions
public List<string> DynamicClaims { get; }
public bool IsRemoteRefreshEnabled { get; set; }
public string RemoteRefreshUrl { get; set; }
public Dictionary<string, List<string>> ClaimsMap { get; set; }
public bool IsDynamicClaimsEnabled { get; set; }
public bool IsDynamicClaimsEnabled { get; set; }
public AbpClaimsPrincipalFactoryOptions()
{
@ -36,6 +38,7 @@ public class AbpClaimsPrincipalFactoryOptions
};
RemoteRefreshUrl = "/api/account/dynamic-claims/refresh";
IsRemoteRefreshEnabled = true;
ClaimsMap = new Dictionary<string, List<string>>()
{

51
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorBase.cs

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Security.Claims;
public abstract class RemoteDynamicClaimsPrincipalContributorBase<TContributor, TContributorCache> : AbpDynamicClaimsPrincipalContributorBase
where TContributor : class
where TContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase<TContributorCache>
{
public async override Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
if (identity == null)
{
return;
}
var userId = identity.FindUserId();
if (userId == null)
{
return;
}
var dynamicClaimsCache = context.GetRequiredService<TContributorCache>().As<TContributorCache>();
AbpDynamicClaimCacheItem dynamicClaims;
try
{
dynamicClaims = await dynamicClaimsCache.GetAsync(userId.Value, identity.FindTenantId());
}
catch (Exception e)
{
// In case if failed refresh remote dynamic cache, We force to clear the claims principal.
context.ClaimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
var logger = context.GetRequiredService<ILogger<TContributor>>();
logger.LogWarning(e, $"Failed to refresh remote dynamic claims cache for user: {userId.Value}");
return;
}
if (dynamicClaims.Claims.IsNullOrEmpty())
{
return;
}
await AddDynamicClaimsAsync(context, identity, dynamicClaims.Claims);
}
}

55
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorCacheBase.cs

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace Volo.Abp.Security.Claims;
public abstract class RemoteDynamicClaimsPrincipalContributorCacheBase<TContributorCache>
{
public ILogger<TContributorCache> Logger { get; set; }
protected IOptions<AbpClaimsPrincipalFactoryOptions> AbpClaimsPrincipalFactoryOptions { get; }
protected RemoteDynamicClaimsPrincipalContributorCacheBase(IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions)
{
AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
Logger = NullLogger<TContributorCache>.Instance;
}
public async Task<AbpDynamicClaimCacheItem> GetAsync(Guid userId, Guid? tenantId = null)
{
Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
var dynamicClaims = await GetCacheAsync(userId, tenantId);
if (dynamicClaims != null)
{
return dynamicClaims;
}
Logger.LogDebug($"Refresh dynamic claims for user: {userId} from remote service.");
try
{
await RefreshAsync(userId, tenantId);
}
catch (Exception e)
{
Logger.LogWarning(e, $"Failed to refresh remote claims for user: {userId}");
throw;
}
dynamicClaims = await GetCacheAsync(userId, tenantId);
if (dynamicClaims == null)
{
throw new AbpException($"Failed to refresh remote claims for user: {userId}");
}
return dynamicClaims;
}
protected abstract Task<AbpDynamicClaimCacheItem?> GetCacheAsync(Guid userId, Guid? tenantId = null);
protected abstract Task RefreshAsync(Guid userId, Guid? tenantId = null);
}

8
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs

@ -25,6 +25,14 @@ public class AbpIdentityDomainModule : AbpModule
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsRemoteRefreshEnabled = false;
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpIdentityDomainModule>();

6
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor.cs

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
@ -34,6 +35,11 @@ public class IdentityDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincip
return;
}
if (dynamicClaims.Claims.IsNullOrEmpty())
{
return;
}
await AddDynamicClaimsAsync(context, identity, dynamicClaims.Claims);
}
}

11
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs

@ -47,6 +47,17 @@ public class IdentityDynamicClaimsPrincipalContributorCache : ITransientDependen
{
Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
if (AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims.IsNullOrEmpty())
{
var emptyCacheItem = new AbpDynamicClaimCacheItem();
await Cache.SetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId), emptyCacheItem, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = CacheOptions.Value.CacheAbsoluteExpiration
});
return emptyCacheItem;
}
return await Cache.GetOrAddAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId), async () =>
{
using (CurrentTenant.Change(tenantId))

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs

@ -232,7 +232,6 @@ public class MyProjectNameBlazorModule : AbpModule
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
options.RemoteRefreshUrl = configuration["AuthServer:Authority"] + options.RemoteRefreshUrl;
});
}

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs

@ -214,7 +214,6 @@ public class MyProjectNameWebModule : AbpModule
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
options.RemoteRefreshUrl = configuration["AuthServer:Authority"] + options.RemoteRefreshUrl;
});
}

Loading…
Cancel
Save