Activities of "alexander.nikonov"

  • ABP Framework version: v8.1.3
  • UI Type: Angular
  • Database System: EF Core (Oracle)
  • Auth Server Separated

Moving to Redis server and dynamic permissions allowed us to simplify the process of Role / Permission management. So now Redis cache contains permissions of all the running solutions.

However, one problem remained: localization. One of the solutions contains Role / Permission management page which displays ALL the permissions. But each permission localized name resides in the corresponding solution. We don't want to move the permission localization to a separate project.

The most simple way to resolve this would be to consume all the solutions' Domain.Shared projects:

    options.Resources
        .Add<PermissionManagementResource>("en")
        .AddBaseTypes(typeof(SolutionAResource), typeof(SolutionBResource), typeof(SolutionCResource))

But it would create a coupling we want to avoid. We might have a new solution D in future - which means we will have to modify the code above again.

The question is - what is an alternative way to have localization from all the solutions always actual, but still be able to do search by a localized name after receiving the permissions from all the solutions using

    var permissionListResultDto = await _permissionAppService.GetAsync(RolePermissionValueProvider.ProviderName, role.Name);
    

?

What is the project of this error log? You can try to add your code to Domain module.

https://abp.io/support/questions/7699/Random-exception-after-switching-from-IdentityServer-to-OpenDict#answer-3a147d57-7267-7eaf-1d74-ba36bdfea929

Sorry, I am not sure I am following you. The first exception (DI issue) needs to be reproduced yet, I am waiting for my colleague trying to assist me, because I did not manage to get this exception. So I cannot say anything here yet.

But instead I received another exception related to the transaction level. According to your recommendation, I have overriden all the stores with the code you provided for the older version of ABP - in order to override a transaction level. After adding this code, I can see that the Store property is properly filled with my custom class. All the constructors of all three custom stores did invoke - so the code was applied as expected. Still, I received the same exception again at some point. I cannot see how this may ever happen, if all my front-end applications interact with the same OpenId Server where I made the override and - I expect - there is only one "entry point" to reach out the TokenCleanupBackgroundWorker where the exception happens and this "entry point" is the interaction between front-end applications and OpenId Server?

I see no problem with this code in the solution where I received the exception - the Store contains correct class:

It was related to using .First inside the loop. And we had many permissions. Replaced IEnumerable with the Dictionary and now it's fine.

Your code is no problem, that strange. Can you share a test project?

Unfortunately I cannot. I only can follow some recommendations. So from what you say I can deduce, that some of the custom store or all of them are not invoked, right? Where should I put the breakpoint in debug?

	using AbxEps.MyApp.AuthServer.Grants;
	using AbxEps.MyApp.AuthServer.Stores;
	using AbxEps.MyApp.Cryptography;
	using AbxEps.MyApp.EntityFrameworkCore;
	using AbxEps.MyApp.Filters;
	using AbxEps.MyApp.Localization;
	using AbxEps.MyApp.Middlewares;
	using AbxEps.MyApp.MultiTenancy;
	using AbxEps.LanguageCodeConvertor.Extensions;
	using AbxEps.Middleware.AbxRequestContext.Extensions;
	using AbxEps.Middleware.CookieAccessToken.Extensions;
	using Localization.Resources.AbpUi;
	using Medallion.Threading;
	using Medallion.Threading.Oracle;
	using Microsoft.AspNetCore.Builder;
	using Microsoft.AspNetCore.Cors;
	using Microsoft.AspNetCore.DataProtection;
	using Microsoft.AspNetCore.Extensions.DependencyInjection;
	using Microsoft.AspNetCore.Mvc;
	using Microsoft.Extensions.Configuration;
	using Microsoft.Extensions.DependencyInjection;
	using Microsoft.Extensions.Hosting;
	using Microsoft.Net.Http.Headers;
	using OpenIddict.Server.AspNetCore;
	using OpenIddict.Validation.AspNetCore;
	using Serilog;
	using StackExchange.Redis;
	using System;
	using System.IO;
	using System.Linq;
	using System.Security.Cryptography.X509Certificates;
	using Volo.Abp;
	using Volo.Abp.Account;
	using Volo.Abp.Account.Public.Web;
	using Volo.Abp.Account.Public.Web.Impersonation;
	using Volo.Abp.Account.Web;
	using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton;
	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling;
	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
	using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpApplicationPath;
	using Volo.Abp.AspNetCore.Serilog;
	using Volo.Abp.Auditing;
	using Volo.Abp.Autofac;
	using Volo.Abp.BackgroundJobs;
	using Volo.Abp.Caching;
	using Volo.Abp.Caching.StackExchangeRedis;
	using Volo.Abp.DistributedLocking;
	using Volo.Abp.FeatureManagement;
	using Volo.Abp.Identity;
	using Volo.Abp.Localization;
	using Volo.Abp.Modularity;
	using Volo.Abp.OpenIddict;
	using Volo.Abp.OpenIddict.Applications;
	using Volo.Abp.OpenIddict.Authorizations;
	using Volo.Abp.OpenIddict.ExtensionGrantTypes;
	using Volo.Abp.OpenIddict.Tokens;
	using Volo.Abp.PermissionManagement;
	using Volo.Abp.Ui.LayoutHooks;
	using Volo.Abp.UI.Navigation.Urls;
	using Volo.Abp.VirtualFileSystem;
	using Volo.Saas.Host;
	using AbxEps.CentralTools.AuthServer.Grants;
	using AbxEps.CentralTools.AuthServer.Stores;
	using AbxEps.CentralTools.Cryptography;
	using AbxEps.CentralTools.Filters;
	using AbxEps.CentralTools.Middlewares;
	using Twilio.Rest.Microvisor.V1;

	namespace AbxEps.MyApp;

	[DependsOn(
		typeof(AbpAutofacModule),
		typeof(AbpCachingStackExchangeRedisModule),
		typeof(AbpDistributedLockingModule),
		typeof(AbpAspNetCoreSerilogModule),
		typeof(AbpAccountPublicWebOpenIddictModule),
		typeof(AbpAccountPublicHttpApiModule),
		typeof(AbpAspNetCoreMvcUiLeptonThemeModule),
		typeof(AbpAccountPublicApplicationModule),
		typeof(AbpAccountPublicWebImpersonationModule),
		typeof(SaasHostApplicationContractsModule),
		typeof(MyAppEntityFrameworkCoreModule)
		)]
	public class MyAppAuthServerModule : AbpModule
	{
		private const string DefaultCorsPolicyName = "Default";

		public override void PreConfigureServices(ServiceConfigurationContext context)
		{
			var configuration = context.Services.GetConfiguration();
			var hostingEnvironment = context.Services.GetHostingEnvironment();

			//var logger = context.Services.GetInitLogger<MyAppAuthServerModule>();

			Log.Information($"*** {nameof(MyAppAuthServerModule)}.{nameof(PreConfigureServices)}: HostingEnvironment: {hostingEnvironment.EnvironmentName}");

			PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
			{
				// https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html
				if (!hostingEnvironment.IsDevelopment())
				{
					options.AddDevelopmentEncryptionAndSigningCertificate = false;
				}
			});

			PreConfigure<OpenIddictServerBuilder>(builder =>
			{
				// https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html

				// not needed because default of AddDevelopmentEncryptionAndSigningCertificate is true in Development...
				/*if (hostingEnvironment.IsDevelopment())
				{
					builder
						.AddDevelopmentEncryptionCertificate()
						.AddDevelopmentSigningCertificate();
				}*/

				if (!hostingEnvironment.IsDevelopment())
				{
					// Encryption
					string encryptionCertThumbPrint = configuration["Certificates:Encryption:ThumbPrint"];
					string encryptionCertFile = configuration["Certificates:Encryption:File"];
					string encryptionCertPassword = configuration["Certificates:Encryption:Password"];

					if (string.IsNullOrEmpty(encryptionCertThumbPrint) && string.IsNullOrEmpty(encryptionCertFile))
					{
						string message = "Neither Certificates:Encryption:ThumbPrint nor Certificates:Encryption:File is set!";
						Log.Error($"*** {message}!");
						throw new NotSupportedException(message);
					}
					if (!string.IsNullOrEmpty(encryptionCertFile) && !File.Exists(encryptionCertFile))
					{
						string message = $"Cannot find encryption certificate '{encryptionCertFile}'!";
						Log.Error($"*** {message}!");
						throw new NotSupportedException(message);
					}

					X509Certificate2 certificate = X509Helper.GetCertificate(encryptionCertThumbPrint, encryptionCertFile, encryptionCertPassword, Log.Logger);

					if (certificate == null)
					{
						// throw exception, stop service...
						string cert = string.IsNullOrEmpty(encryptionCertThumbPrint) ? encryptionCertFile : encryptionCertThumbPrint;
						throw new NotSupportedException($"Encryption Certificate '{cert}' not found!");
					}
					else
					{
						Log.Debug($"Encryption Certificate: Issuer is '{certificate.Issuer}'");
						builder.AddEncryptionCertificate(certificate);
					}

					// Signing Certificate
					string signingCertThumbPrint = configuration["Certificates:Signing:ThumbPrint"];
					string signingCertFile = configuration["Certificates:Signing:file"];
					string signingCertPassword = configuration["Certificates:Signing:Password"];

					if (string.IsNullOrEmpty(signingCertThumbPrint) && string.IsNullOrEmpty(signingCertFile))
					{
						string message = "Neither Certificates:Signing:ThumbPrint nor Certificates:Signing:File is set!";
						Log.Error($"*** {message}!");
						throw new NotSupportedException(message);
					}
					if (!string.IsNullOrEmpty(signingCertFile) && !File.Exists(signingCertFile))
					{
						string message = $"Cannot find signing certificate '{signingCertFile}'!";
						Log.Error($"*** {message}!");
						throw new NotSupportedException(message);
					}

					certificate = X509Helper.GetCertificate(signingCertThumbPrint, signingCertFile, signingCertPassword, Log.Logger);

					if (certificate == null)
					{
						// throw exception, stop service...
						string cert = string.IsNullOrEmpty(signingCertThumbPrint) ? signingCertFile : signingCertThumbPrint;
						throw new NotSupportedException($"Signing Certificate '{cert}' not found!");
					}
					else
					{
						Log.Debug($"Signing Certificate: Issuer is '{certificate.Issuer}'");
						builder.AddSigningCertificate(certificate);
					}
				}

				builder.Configure(options =>
				{
					// adobu TODO
					// https://documentation.openiddict.com/configuration/token-formats.html#disabling-jwt-access-token-encryption
					// DisableAccessTokenEncryption is set to true in Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule.AddOpenIddictServer
					// options.DisableAccessTokenEncryption = false;

					//options.GrantTypes.Add(AbxLoginGrant.ExtensionGrantName);
					options.GrantTypes.Add(SwitchToTenantGrant.ExtensionGrantName);
				});
			});

			PreConfigure<OpenIddictBuilder>(builder =>
			{
				builder.AddValidation(options =>
				{
					options.AddAudiences("MyApp");
					options.UseLocalServer();
					options.UseAspNetCore();
				});
			});
		}

		public override void ConfigureServices(ServiceConfigurationContext context)
		{
			var hostingEnvironment = context.Services.GetHostingEnvironment();
			var configuration = context.Services.GetConfiguration();

			if (!Convert.ToBoolean(configuration["App:DisablePII"]))
			{
				Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
			}

			if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]))
			{
				Configure<OpenIddictServerAspNetCoreOptions>(options =>
				{
					options.DisableTransportSecurityRequirement = true;
				});
			}

			context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);

			// This is added for a correct root path in js files
			Configure<AbpLayoutHookOptions>(options =>
			{
				options.Add(LayoutHooks.Head.Last,
				typeof(AbpApplicationPathViewComponent));
			});

			Configure<AbpLocalizationOptions>(options =>
			{
				options.Resources
					.Get<MyAppResource>()
					.AddBaseTypes(
						typeof(AbpUiResource)
					);
			});

			Configure<AbpBundlingOptions>(options =>
			{
				options.StyleBundles.Configure(
					LeptonThemeBundles.Styles.Global,
					bundle =>
					{
						bundle.AddFiles("/global-styles.css");
					}
				);
			});

			Configure<AbpAuditingOptions>(options =>
			{
				//options.IsEnabledForGetRequests = true;
				options.ApplicationName = "AuthServer";
			});

			if (hostingEnvironment.IsDevelopment())
			{
				Configure<AbpVirtualFileSystemOptions>(options =>
				{
					options.FileSets.ReplaceEmbeddedByPhysical<MyAppDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}AbxEps.MyApp.Domain.Shared", Path.DirectorySeparatorChar)));
					options.FileSets.ReplaceEmbeddedByPhysical<MyAppDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}AbxEps.MyApp.Domain", Path.DirectorySeparatorChar)));
				});
			}

			Configure<AppUrlOptions>(options =>
			{
				options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
				options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));
				options.Applications["Angular"].RootUrl = configuration["App:AngularUrl"];
				options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password";
				options.Applications["Angular"].Urls[AccountUrlNames.EmailConfirmation] = "account/email-confirmation";
			});

			Configure<AbpBackgroundJobOptions>(options =>
			{
				options.IsJobExecutionEnabled = false;
			});

			Configure<AbpDistributedCacheOptions>(options =>
			{
				options.KeyPrefix = "Abx:";
			});

			Configure<MvcOptions>(options =>
			{
				options.Filters.Add(typeof(TokenExpiredExceptionFilter));
			});

			var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("MyApp");
			if (!hostingEnvironment.IsDevelopment())
			{
				var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
				dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "AuthServer-Protection-Keys");
			}

			context.Services.AddSingleton<IDistributedLockProvider>(sp =>
			{
				//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
				//return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
				return new OracleDistributedSynchronizationProvider(configuration["ConnectionStrings:Default"]);
			});

			ConfigureCors(context, configuration);
			ConfigureAuth(context, configuration);
			ConfigureOpenIdDict(context, configuration);
			ConfigureStores(context, configuration);

			context.Services.Configure<AbpAccountOptions>(options =>
			{
				options.TenantAdminUserName = "admin";
				options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
				options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
			});

			Configure<PermissionManagementOptions>(options =>
			{
				options.IsDynamicPermissionStoreEnabled = true;
			});

			Configure<FeatureManagementOptions>(options =>
			{
				options.IsDynamicFeatureStoreEnabled = true;
			});
		}

		private static void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
		{
			context.Services.AddCors(options =>
			{
				options.AddPolicy(DefaultCorsPolicyName, builder =>
				{
					builder
						.WithOrigins(
							configuration["App:CorsOrigins"]
								.Split(",", StringSplitOptions.RemoveEmptyEntries)
								.Select(o => o.Trim().RemovePostFix("/"))
								.ToArray()
						)
						.WithAbpExposedHeaders()
						.SetIsOriginAllowedToAllowWildcardSubdomains()
						.AllowAnyHeader()
						.AllowAnyMethod()
						.AllowCredentials();
				});
			});
		}

		private static void ConfigureAuth(ServiceConfigurationContext context, IConfiguration configuration)
		{
			context.Services.AddAuthentication();
		}

		private static void ConfigureStores(ServiceConfigurationContext context, IConfiguration configuration)
		{
			context.Services.AddOpenIddict()
				.AddCore(builder =>
				{
					builder
						.AddApplicationStore<AbxAbpOpenIddictApplicationStore>()
						.AddAuthorizationStore<AbxAbpOpenIddictAuthorizationStore>()
						.AddTokenStore<AbxAbpOpenIddictTokenStore>();
				});
		}

		private void ConfigureOpenIdDict(ServiceConfigurationContext context, IConfiguration configuration)
		{
			// Configure<TokenCleanupOptions>(options => { });

			Configure<AbpOpenIddictExtensionGrantsOptions>(options =>
			{
				//options.Grants.Add(AbxLoginGrant.ExtensionGrantName, new AbxLoginGrant());
				options.Grants.Add(SwitchToTenantGrant.ExtensionGrantName, new SwitchToTenantGrant());
			});

			// This is required for working of AbxRequestContext
			context.Services.AddHttpContextAccessor();
			context.Services.InitLanguageCodeConvertor(configuration);
			context.Services.InitAbxRequestContext();
		}

		public override void OnApplicationInitialization(ApplicationInitializationContext context)
		{

			var app = context.GetApplicationBuilder();
			var env = context.GetEnvironment();

			if (env.IsDevelopment())
			{
				app.UseDeveloperExceptionPage();
			}

			app.UseAbpRequestLocalization();

			if (!env.IsDevelopment())
			{
				app.UseErrorPage();
			}

			app.UseCorrelationId();
			app.UseAbpSecurityHeaders();
			app.UseStaticFiles();
			app.UseRouting();
			app.UseCors(DefaultCorsPolicyName);
			app.UseAuthentication();
			//app.UseAbpOpenIddictValidation();  // UseIdentityServer
			app.UseCookieAccessTokenDelete(HeaderNames.Authorization);

			/* https://docs.abp.io/en/abp/7.0/Migration-Guides/IdentityServer_To_OpenIddict
			app.UseJwtTokenMiddleware();*/

			if (MultiTenancyConsts.IsEnabled)
			{
				app.UseMultiTenancy();
			}

			app.UseUnitOfWork();
			app.UseMiddleware<SessionEndAuditingMiddleware>();
			app.UseMiddleware<TenantSwitchMiddleware>();

			app.UseAbpOpenIddictValidation();  // UseIdentityServer
			app.UseAuthorization();

			app.UseAuditing();
			app.UseAbpSerilogEnrichers();
			app.UseConfiguredEndpoints();
		}
	}

So while the initial exception reproducing still pending, I received this again:

> [09:26:33 INF] Lock is acquired for TokenCleanupBackgroundWorker
> [09:26:33 INF] Start cleanup.
> [09:26:33 INF] Start cleanup tokens.
> fail: Microsoft.EntityFrameworkCore.Infrastructure[0]
> 2024-08-19 09:26:34.569195 ThreadID:500 (ERROR)   OracleExecutionStrategy.ExecuteAsync() :  System.ArgumentException: IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
> at Oracle.ManagedDataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
> at Oracle.ManagedDataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
> at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
> --- End of stack trace from previous location ---
> at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
> at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
> [09:26:34 ERR] IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
> System.ArgumentException: IsolationLevel must be ReadCommitted or Serializable (Parameter 'isolationLevel')
> at Oracle.ManagedDataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
> at Oracle.ManagedDataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
> at System.Data.Common.DbConnection.BeginDbTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
> --- End of stack trace from previous location ---
> at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.BeginTransactionAsync(IsolationLevel isolationLevel, CancellationToken cancellationToken)
> at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
> at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
> at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork)
> at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString)
> at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync()
> at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetDbSetAsync()
> at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetQueryableAsync()
> at Volo.Abp.OpenIddict.Tokens.EfCoreOpenIddictTokenRepository.PruneAsync(DateTime date, CancellationToken cancellationToken)
> at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
> at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
> at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
> at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
> at Volo.Abp.OpenIddict.Tokens.AbpOpenIddictTokenStore.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
> at Volo.Abp.OpenIddict.Tokens.TokenCleanupService.CleanAsync()

And it is happening after I replaced all the stores as you suggested. The code of the stores was copy-pasted from yours:

context.Services.AddOpenIddict()
    .AddCore(builder =>
    {
        builder
            .AddApplicationStore<AbxAbpOpenIddictApplicationStore>()
            .AddAuthorizationStore<AbxAbpOpenIddictAuthorizationStore>()
            .AddTokenStore<AbxAbpOpenIddictTokenStore>();
    });

Maybe I am adding this code too late inside ConfigureServices if the order matters at all here? What is it supposed to follow in OpenIDServer module?

Please share full request and response logs.

Sorry - my bad (due to very late time here). I've updated the message above. So it is seen the time is spent here. But there is no more information:

2024-08-16 04:25:17.610 -05:00 [DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:55.009 -05:00 [DBG] Added 0 entity changes to the current audit log

Please check the log. The log will contain the time taken to read and write redis.

The situation is interesting. The log does not show a huge timing:

2024-08-16 04:25:13.454 -05:00 [INF] Request starting HTTP/1.1 GET https://localhost:44328/api/module-permission/roles/module/as-permissions?sorting=displayName%20asc&skipCount=0&maxResultCount=12000&isModuleRole=true&isGranted=true&id=d941cfc0-74b7-06b1-cb98-39fefb5fa915 - null null 2024-08-16 04:25:13.454 -05:00 [INF] CORS policy execution successful. 2024-08-16 04:25:14.725 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:f6bfc02f-4400-1256-f3db-39fed7dc74b6,n:AbpIdentity.Roles 2024-08-16 04:25:14.728 -05:00 [DBG] Found in the cache: pn:U,pk:f6bfc02f-4400-1256-f3db-39fed7dc74b6,n:AbpIdentity.Roles 2024-08-16 04:25:14.733 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:14.735 -05:00 [DBG] Found in the cache: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:14.736 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:14.737 -05:00 [DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:14.738 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:CentralTools_App,n:AbpIdentity.Roles 2024-08-16 04:25:14.739 -05:00 [DBG] Found in the cache: pn:C,pk:CentralTools_App,n:AbpIdentity.Roles 2024-08-16 04:25:14.803 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:14.804 -05:00 [DBG] Found in the cache: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:14.804 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:14.806 -05:00 [DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:17.423 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:17.424 -05:00 [INF] Executing endpoint 'AbxEps.CentralTools.Controllers.ModulePermissions.ModulePermissionController.GetModuleRolesAsPermissionsAsync (AbxEps.CentralTools.HttpApi)' 2024-08-16 04:25:17.434 -05:00 [INF] Route matched with {area = "app", controller = "ModulePermission", action = "GetModuleRolesAsPermissions", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Volo.Abp.Application.Dtos.PagedResultDto1[Volo.Abp.PermissionManagement.PermissionGrantInfoDto]] GetModuleRolesAsPermissionsAsync(AbxEps.CT.ModulePermission.Roles.GetRolePermissionsInput) on controller AbxEps.CentralTools.Controllers.ModulePermissions.ModulePermissionController (AbxEps.CentralTools.HttpApi). 2024-08-16 04:25:17.601 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:f6bfc02f-4400-1256-f3db-39fed7dc74b6,n:AbpIdentity.Roles 2024-08-16 04:25:17.603 -05:00 [DBG] Found in the cache: pn:U,pk:f6bfc02f-4400-1256-f3db-39fed7dc74b6,n:AbpIdentity.Roles 2024-08-16 04:25:17.603 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:17.604 -05:00 [DBG] Found in the cache: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:17.604 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:17.605 -05:00 [DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:17.605 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:CentralTools_App,n:AbpIdentity.Roles 2024-08-16 04:25:17.606 -05:00 [DBG] Found in the cache: pn:C,pk:CentralTools_App,n:AbpIdentity.Roles 2024-08-16 04:25:17.608 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:17.609 -05:00 [DBG] Found in the cache: pn:R,pk:Role 1,n:AbpIdentity.Roles 2024-08-16 04:25:17.609 -05:00 [DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:17.610 -05:00 [DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Roles 2024-08-16 04:25:55.009 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.017 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.025 -05:00 [INF] Executing ObjectResult, writing value of type 'Volo.Abp.Application.Dtos.PagedResultDto`1[[Volo.Abp.PermissionManagement.PermissionGrantInfoDto, Volo.Abp.PermissionManagement.Application.Contracts, Version=8.1.3.0, Culture=neutral, PublicKeyToken=null]]'. 2024-08-16 04:25:55.036 -05:00 [INF] Executed action AbxEps.CentralTools.Controllers.ModulePermissions.ModulePermissionController.GetModuleRolesAsPermissionsAsync (AbxEps.CentralTools.HttpApi) in 37601.7587ms 2024-08-16 04:25:55.036 -05:00 [INF] Executed endpoint 'AbxEps.CentralTools.Controllers.ModulePermissions.ModulePermissionController.GetModuleRolesAsPermissionsAsync (AbxEps.CentralTools.HttpApi)' 2024-08-16 04:25:55.037 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.040 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.569 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.570 -05:00 [DBG] Added 0 entity changes to the current audit log 2024-08-16 04:25:55.571 -05:00 [INF] Request finished HTTP/1.1 GET https://localhost:44328/api/module-permission/roles/module/as-permissions?sorting=displayName%20asc&skipCount=0&maxResultCount=12000&isModuleRole=true&isGranted=true&id=d941cfc0-74b7-06b1-cb98-39fefb5fa915 - 200 24713 application/json; charset=utf-8 42117.6325ms

The DB is remote, everything the rest is localhost. But when there was no Redis - the timing was much better.

I did not transfer these lines to the project which now is responsible for Role Management:

    Configure<PermissionManagementOptions>(options =>
    {
        options.ManagementProviders.Add<ModulePermissionManagementProvider>();
        options.ProviderPolicies[ModulePermissionRoleValueProvider.ProviderName] = ModulePermissionConsts.RoleSubGroupName;
    });
    

After I added this, the permissions are properly reflected.

But I have noticed that now after moving to dynamic permissions and Redis, selecting the permissions (basically, invoking the method above) is very slow. Can it only be related to Redis? All Redis settings are default:

Showing 21 to 30 of 317 entries
Made with ❤️ on ABP v9.0.0-preview Updated on September 19, 2024, 10:13