Starts in:
2 DAYS
0 HR
42 MIN
14 SEC
Starts in:
2 D
0 H
42 M
14 S
Open Closed

How to force adding PermissionDefinitionProvider only after the user is authenticated? #5799


User avatar
0
alexander.nikonov created
  • ABP Framework version: v7.0.1
  • UI Type: Angular
  • Database System: EF Core (Oracle)
  • Auth Server Separated

I have custom Permission Definition Provider:

    using AbxEps.CT.Core.Extensions;
    using AbxEps.CT.Core.Localization;
    using AbxEps.CT.Core.PortalMenu;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Threading.Tasks;
    using Volo.Abp.Authorization.Permissions;
    using Volo.Abp.Localization;
    using Volo.Abp.Threading;
    using Volo.Abp.Users;

    namespace AbxEps.CT.Core.Permissions
    {
        public class CorePermissionDefinitionProvider : PermissionDefinitionProvider
        {
            private readonly ICurrentUser _currentUser;
            private readonly IAbxPortalsMenuAppService _abxPortalsMenuAppService;
    
            public CorePermissionDefinitionProvider
            (
                IAbxPortalsMenuAppService abxPortalsMenuAppService,
                ICurrentUser currentUser
             )
            {
                _abxPortalsMenuAppService = abxPortalsMenuAppService;
                _currentUser = currentUser;
            }
    
            public override void Define(IPermissionDefinitionContext context)
            {
                var coreCtGroup = context.AddGroup(CorePermissions.GroupName, L("Permission:Core"));
                var fileMngPermission = coreCtGroup.AddPermission(CorePermissions.FileManager.Read, L("Permission:FileManager:Read"));
                fileMngPermission.AddChild(CorePermissions.FileManager.Modify, L("Permission:FileManager:Modify"));
                if (_currentUser.IsAuthenticated)
                {
                    AsyncHelper.RunSync(() => InitPortalAccessPermissionsAsync(context)); // Not called, because when the host is started the user is still not authenticated - so "if" condition is not invoked
                }
            }
    
            private async Task InitPortalAccessPermissionsAsync(IPermissionDefinitionContext context)
            {
                ...
            }
        }
    }
        

Whereas the permissions which are supposed to be added unconditionally (fileMngPermissions) are added successfully when host is running, the permissions which need to be added only after the user is authenticated (portalAccessPermissions) are obviously not added and not visible via IPermissionAppService:

    var allPermissionsForRole = await _permissionAppService.GetAsync("R", "Role 1");
    

How to add a whole CorePermissionDefinitionProvider or the part of its relevant permissions (portalAccessPermissions) conditionally - once the user got authenticated?

P.S. I'd prefer not to use Middleware, because its Invoke method is invoked on each request. Instead, I need to add my CorePermissionDefinitionProvider or its authentication-related permissions once after the user authentication was successful. I use external authentication via Identity Server. So this functionality needs to reside inside the application project, not Identity Server project.

Making PermissionDefinitionManager a ITransientDependency (or probably I can make CorePermissionDefinitionProvider transient too) does not sound good either: I dot not want to trigger the check each time. I just need to trigger it ONCE, but after the user has been authenticated.


28 Answer(s)
  • User Avatar
    0
    alexander.nikonov created

    Sure.

    3 files here: Extension class which makes use of this "dynamic" provider,

    overridden Static Store where the exception happens:

    var providers = Options
        .DefinitionProviders
        .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider)
        .ToList()
    

    if I don't use the Configure<AbpPermissionOptions> approach

    and the PortalAccessPermissionDefinitionProvider itself.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    DisableConventionalRegistration will not add services to the DI container. so OnRegistered will not call. this is strange

    https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs#L69-L75

  • User Avatar
    0
    alexander.nikonov created

    Well, at least it's possible make it working using AbpPermissionOptions.. I don't know why it requires it. But seems like I managed to make "dynamic" permission definition provider work properly combining "static" and "dynamic" values:

        private IDictionary&lt;string, PermissionGroupDefinition&gt; _dynamicPermissionGroupDefinitions = new Dictionary&lt;string, PermissionGroupDefinition&gt;();
        protected IDictionary&lt;string, PermissionGroupDefinition&gt; PermissionGroupDefinitions
        {
            get
            {
                var staticGroupDefinitions = _lazyPermissionGroupDefinitions.Value;
                var combinedGroupDefinitions = new Dictionary&lt;string, PermissionGroupDefinition&gt;(staticGroupDefinitions);
                foreach (var userAddedGroupDefinition in _dynamicPermissionGroupDefinitions)
                {
                    combinedGroupDefinitions[userAddedGroupDefinition.Key] = userAddedGroupDefinition.Value;
                }
                return combinedGroupDefinitions;
            }
        }
        private readonly Lazy&lt;Dictionary&lt;string, PermissionGroupDefinition&gt;> _lazyPermissionGroupDefinitions;
    
        private IDictionary&lt;string, PermissionDefinition&gt; _dynamicPermissionDefinitions = new Dictionary&lt;string, PermissionDefinition&gt;();
        protected IDictionary&lt;string, PermissionDefinition&gt; PermissionDefinitions
        {
            get
            {
                var staticDefinitions = _lazyPermissionDefinitions.Value;
                var combinedDefinitions = new Dictionary&lt;string, PermissionDefinition&gt;(staticDefinitions);
                foreach (var userAddedDefinition in _dynamicPermissionDefinitions)
                {
                    combinedDefinitions[userAddedDefinition.Key] = userAddedDefinition.Value;
                }
                return combinedDefinitions;
            }
        }
        private readonly Lazy&lt;Dictionary&lt;string, PermissionDefinition&gt;> _lazyPermissionDefinitions;
    
        protected AbpPermissionOptions Options { get; }
    
        private readonly IServiceProvider _serviceProvider;
    
        public ExtendedStaticPermissionDefinitionStore(
            IServiceProvider serviceProvider,
            IOptions&lt;AbpPermissionOptions&gt; options)
        {
            _serviceProvider = serviceProvider;
            Options = options.Value;
    
            _lazyPermissionDefinitions = new Lazy&lt;Dictionary&lt;string, PermissionDefinition&gt;>(
                CreatePermissionDefinitions,
                isThreadSafe: true
            );
    
            _lazyPermissionGroupDefinitions = new Lazy&lt;Dictionary&lt;string, PermissionGroupDefinition&gt;>(
                CreatePermissionGroupDefinitions,
                isThreadSafe: true
            );
        }
    
        public void AddPermissionDefinitionProvider(IPermissionDefinitionProvider permissionDefinitionProvider)
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var context = new PermissionDefinitionContext(scope.ServiceProvider);
    
                permissionDefinitionProvider.PreDefine(context);
                permissionDefinitionProvider.Define(context);
                permissionDefinitionProvider.PostDefine(context);
    
                foreach (var group in context.Groups)
                {
                    _dynamicPermissionGroupDefinitions[group.Key] = group.Value;
                }
    
                var permissions = new Dictionary&lt;string, PermissionDefinition&gt;();
    
                foreach (var groupDefinition in _dynamicPermissionGroupDefinitions.Values)
                {
                    foreach (var permission in groupDefinition.Permissions)
                    {
                        AddPermissionToDictionaryRecursively(permissions, permission);
                    }
                }
    
                foreach (var permission in permissions)
                {
                    _dynamicPermissionDefinitions[permission.Key] = permission.Value;
                }
            }
        }
        
    

    Probably would come in handy for someone. Closing the ticket... Thanks for inspiration!

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06