diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index 42339a60ac..c06ede33c1 100644
--- a/framework/Volo.Abp.sln
+++ b/framework/Volo.Abp.sln
@@ -463,6 +463,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp.Tests", "test\Volo.Abp.Imaging.SkiaSharp.Tests\Volo.Abp.Imaging.SkiaSharp.Tests.csproj", "{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims", "src\Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims\Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims.csproj", "{6F72FFCE-0183-4EF1-80B6-8FC3268E8E99}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1381,6 +1383,10 @@ Global
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6F72FFCE-0183-4EF1-80B6-8FC3268E8E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F72FFCE-0183-4EF1-80B6-8FC3268E8E99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F72FFCE-0183-4EF1-80B6-8FC3268E8E99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F72FFCE-0183-4EF1-80B6-8FC3268E8E99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1614,6 +1620,7 @@ Global
{F19A6E0C-F719-4ED9-A024-14E4B8D40883} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{198683D0-7DC6-40F2-B81B-8E446E70A9DE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
+ {6F72FFCE-0183-4EF1-80B6-8FC3268E8E99} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims.csproj
new file mode 100644
index 0000000000..d02a8df68c
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims.csproj
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ net8.0
+ enable
+ Nullable
+ Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/AbpAspNetCoreAuthenticationJwtBearerDynamicClaimsModule.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/AbpAspNetCoreAuthenticationJwtBearerDynamicClaimsModule.cs
new file mode 100644
index 0000000000..a21bf70d6d
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/AbpAspNetCoreAuthenticationJwtBearerDynamicClaimsModule.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Caching;
+using Volo.Abp.Modularity;
+using Volo.Abp.Security.Claims;
+
+namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
+
+[DependsOn(
+ typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
+ typeof(AbpCachingModule)
+)]
+public class AbpAspNetCoreAuthenticationJwtBearerDynamicClaimsModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.AddHttpClient();
+ context.Services.AddHttpContextAccessor();
+ var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions();
+ if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
+ {
+ context.Services.AddTransient();
+ context.Services.AddTransient();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs
new file mode 100644
index 0000000000..454977b4b6
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/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
+{
+
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
new file mode 100644
index 0000000000..3a3b16131d
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/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
+{
+ public const string HttpClientName = nameof(WebRemoteDynamicClaimsPrincipalContributorCache);
+
+ protected IDistributedCache Cache { get; }
+ protected IHttpClientFactory HttpClientFactory { get; }
+ protected IHttpContextAccessor HttpContextAccessor { get; }
+ protected IOptions Options { get; }
+
+ public WebRemoteDynamicClaimsPrincipalContributorCache(
+ IDistributedCache cache,
+ IHttpClientFactory httpClientFactory,
+ IOptions abpClaimsPrincipalFactoryOptions,
+ IHttpContextAccessor httpContextAccessor,
+ IOptions options)
+ : base(abpClaimsPrincipalFactoryOptions)
+ {
+ Cache = cache;
+ HttpClientFactory = httpClientFactory;
+ HttpContextAccessor = httpContextAccessor;
+ Options = options;
+ }
+
+ protected async override Task 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;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs
new file mode 100644
index 0000000000..960ebbb38c
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims/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;
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
index d3734e7c66..b7cd9d3a30 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
+++ b/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();
context.Services.AddTransient();
+
+ var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions();
+ if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
+ {
+ context.Services.AddTransient();
+ context.Services.AddTransient();
+ }
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
index 2ab437b319..ae88d00ef8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
@@ -1,50 +1,10 @@
-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;
+using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
-public class RemoteDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
+[DisableConventionalRegistration]
+public class RemoteDynamicClaimsPrincipalContributor : RemoteDynamicClaimsPrincipalContributorBase
{
- 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();
- 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>();
- 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);
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs
index 9dac39c786..738884fe06 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs
+++ b/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
{
public const string HttpClientName = nameof(RemoteDynamicClaimsPrincipalContributorCache);
- public ILogger Logger { get; set; }
protected IDistributedCache Cache { get; }
protected IHttpClientFactory HttpClientFactory { get; }
- protected IOptions AbpClaimsPrincipalFactoryOptions { get; }
protected IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
public RemoteDynamicClaimsPrincipalContributorCache(
@@ -28,25 +24,20 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
IHttpClientFactory httpClientFactory,
IOptions abpClaimsPrincipalFactoryOptions,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator)
+ : base(abpClaimsPrincipalFactoryOptions)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
- AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
HttpClientAuthenticator = httpClientAuthenticator;
-
- Logger = NullLogger.Instance;
}
- public virtual async Task GetAsync(Guid userId, Guid? tenantId = null)
+ protected async override Task 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)
- {
- throw new AbpException($"Failed to refresh remote claims for user: {userId}");
- }
-
- return dynamicClaims;
}
}
diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs
index 75bf67bee6..b738aa54d5 100644
--- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs
+++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs
@@ -12,11 +12,13 @@ public class AbpClaimsPrincipalFactoryOptions
public List DynamicClaims { get; }
+ public bool IsRemoteRefreshEnabled { get; set; }
+
public string RemoteRefreshUrl { get; set; }
public Dictionary> 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";
+ IsDynamicClaimsEnabled = true;
ClaimsMap = new Dictionary>()
{
diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorBase.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorBase.cs
new file mode 100644
index 0000000000..7c7c392157
--- /dev/null
+++ b/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 : AbpDynamicClaimsPrincipalContributorBase
+ where TContributor : class
+ where TContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase
+{
+ 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().As();
+ 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>();
+ 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);
+ }
+}
diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorCacheBase.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/RemoteDynamicClaimsPrincipalContributorCacheBase.cs
new file mode 100644
index 0000000000..cc576da441
--- /dev/null
+++ b/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
+{
+ public ILogger Logger { get; set; }
+
+ protected IOptions AbpClaimsPrincipalFactoryOptions { get; }
+
+ protected RemoteDynamicClaimsPrincipalContributorCacheBase(IOptions abpClaimsPrincipalFactoryOptions)
+ {
+ AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task GetAsync(Guid userId, Guid? tenantId = null)
+ {
+ Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
+ var dynamicClaims = await GetCacheAsync(userId, tenantId);
+ if (dynamicClaims != null && !dynamicClaims.Claims.IsNullOrEmpty())
+ {
+ 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 GetCacheAsync(Guid userId, Guid? tenantId = null);
+
+ protected abstract Task RefreshAsync(Guid userId, Guid? tenantId = null);
+}
diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs
index 354e7e4586..49f353153b 100644
--- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs
+++ b/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(options =>
+ {
+ options.IsRemoteRefreshEnabled = false;
+ });
+ }
+
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper();
diff --git a/nupkg/common.ps1 b/nupkg/common.ps1
index 78de2aef44..db18b918b3 100644
--- a/nupkg/common.ps1
+++ b/nupkg/common.ps1
@@ -95,6 +95,7 @@ $projects = (
# framework
"framework/src/Volo.Abp.ApiVersioning.Abstractions",
"framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer",
+ "framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims",
"framework/src/Volo.Abp.AspNetCore.Authentication.OAuth",
"framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect",
"framework/src/Volo.Abp.AspNetCore",
diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs
index c41ed749be..e456ede4f3 100644
--- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs
+++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs
@@ -232,7 +232,6 @@ public class MyProjectNameBlazorModule : AbpModule
context.Services.Configure(options =>
{
options.IsDynamicClaimsEnabled = true;
- options.RemoteRefreshUrl = configuration["AuthServer:Authority"] + options.RemoteRefreshUrl;
});
}
diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
index 70e98a64eb..777d3e8886 100644
--- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
+++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
@@ -214,7 +214,6 @@ public class MyProjectNameWebModule : AbpModule
context.Services.Configure(options =>
{
options.IsDynamicClaimsEnabled = true;
- options.RemoteRefreshUrl = configuration["AuthServer:Authority"] + options.RemoteRefreshUrl;
});
}