Open Closed

Composite role implementation (role of roles) #4850


User avatar
0
alexander.nikonov created
  • ABP Framework version: v7.0.1
  • UI type: Angular
  • DB provider: EF Core
  • Identity Server Separated (Angular)

We would like to implement the logic which implies assigning permissions to a custom role, while such custom role in turn is assigned to a standard role of the system. Could you please advice how can we fulfil such task by means of ABP framework?


41 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    This sounds like another version of the user-role: customRole-role.

    You can check the implementation code of module Identity: https://github.com/abpframework/abp/tree/dev/modules/identity

    Some point:

    • Feature management Ui is reusable, and you can use it directly: https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html#L33
    • You need to cover the role permission provider to load the permissions of the custom role under the role: https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs#L40
    • You need to delete the permission cache when updating and deleting custom roles. for example: https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs
  • User Avatar
    0
    alper created
    Support Team

    the question re-opened due the owner's request.

  • User Avatar
    0
    alexander.nikonov created

    Looks like I will need to create another table, similar to ABPUSERROLES - to bind bottom-level roles to a top-level role. What I don't like in this approach - there will be no difference between both types of roles (just role name encoded in a special way) - ABPROLES does not have some suitable fields for this purpose: it needs to be allowed to assign a bottom-level role to a top-level role, but not vice-versa.

  • User Avatar
    0
    liangshiwei created
    Support Team

    ABPROLES does not have some suitable fields for this purpose

    No such fields, you can consider to extending entities: https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities

  • User Avatar
    0
    alexander.nikonov created

    ABPROLES does not have some suitable fields for this purpose

    No such fields, you can consider to extending entities: https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities

    Ok, thanks. We will consider it. Please, do not close the ticket though, we might come up with other questions - the implementation is in progress...

  • User Avatar
    0
    alexander.nikonov created

    BTW, what the ABP tables with "_SAVE" suffix are for? E.g., I can see ABPUSERROLES and ABPUSERROLES_SAVE... the structure is the same...

  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi

    Sorry,I didn’t quite understand what’s you mean.

    As far as I know there is no ABPUSERROLES_SAVE.

    Can you explain it in detail?

  • User Avatar
    0
    alexander.nikonov created

    We have several ABP tables with "_SAVE" suffix. I thought it was created on purpose by ABP. But if it is not - I suppose it is some backup (or default value storage) done manually by someone in the team. Please confirm you have no any such, so I will ask the team about them:

  • User Avatar
    0
    alper created
    Support Team

    ABP doesn't create tables with a _SAVE suffix. I guess your team is creating backups of important tables.

  • User Avatar
    0
    alexander.nikonov created

    I can see there are PermissionValueProvider and PermissionManagementProvider ABP providers. Do I need to create both? I did it and added them to my domain module like so:

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<AbpPermissionOptions>(options =>
            {
                options.ValueProviders.Add<AbxModuleRolePermissionValueProvider>();
            });
    
            Configure<PermissionManagementOptions>(options =>
            {
                options.ProviderPolicies.Add(AbxModuleRolePermissionValueProvider.ProviderName, AbxModuleRolePermissionValueProvider.ProviderName); // "MR"
                options.ManagementProviders.Add<AbxModuleRolePermissionManagementProvider>();
            });
            ...
        }
        
    

    However, when I reference provider name (AbxModuleRolePermissionValueProvider.ProviderName) via DI-ed ABP IPermissionAppService in my configuring page of the project

    I am getting the following error:

    No policy found: 'MR'

  • User Avatar
    0
    liangshiwei created
    Support Team

    You need to define permission for AbxModuleRolePermissionValueProvider

    • https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityPermissionDefinitionProvider.cs#L23
    • https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs#L21
  • User Avatar
    0
    alexander.nikonov created

    Thank you. OK - on Application.Contracts layer i've created AbxModuleRolePermissionDefinitionProvider where I defined all "so-called" permissions (according to our requirements - second-level roles):

    public class AbxModuleRolePermissionDefinitionProvider : PermissionDefinitionProvider
    {
        public override void Define(IPermissionDefinitionContext context)
        {
            var currentUser = context.ServiceProvider.GetService<ICurrentUser>();
    
            if (currentUser.IsAuthenticated)
            {
                var moduleRoleGroup = context.AddGroup(ModuleRolePermissions.GroupName, L("Permission:ModuleRoleManagement"));
    
                var moduleRoleAppService = context.ServiceProvider.GetService<IModuleRoleAppService>();
    
                var moduleRoles = moduleRoleAppService.GetModuleRolesAsync(new GetModuleRolesInput()).Result;
    
                for (var i = 0; i < moduleRoles.Items.Count; i++)
                {
                    moduleRoleGroup.AddPermission(moduleRoles.Items[i].Name).WithProviders("MR");
                }
            }
        }
    
        private static LocalizableString L(string name)
        {
            return LocalizableString.Create<CoreResource>(name);
        }
    

    I also put the line related to policies into Module:

        Configure<AbpPermissionOptions>(options =>
        {
            options.ValueProviders.Add<AbxModuleRolePermissionValueProvider>();
        });
    
        Configure<PermissionManagementOptions>(options =>
        {
            options.ProviderPolicies[AbxModuleRolePermissionValueProvider.ProviderName] = "WHAT_IS_IT";
            options.ManagementProviders.Add<AbxModuleRolePermissionManagementProvider>();
        });
    

    And this list is successfully loaded on my page (see the grid below). But nevertheless, when I try to update the permissions with the code in the first post, I'm getting the same error.

  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    Is there a permission definition called WHAT_IS_IT?

    You need to:

    public class AbxModuleRolePermissionDefinitionProvider : PermissionDefinitionProvider
    {
        public override void Define(IPermissionDefinitionContext context)
        {
      
            var moduleRoleGroup = context.AddGroup(ModuleRolePermissions.GroupName, L("Permission:ModuleRoleManagement"));
            
            moduleRoleGroup.AddChild("AbxModuleRole",....)
        }
     }
     
    Configure<PermissionManagementOptions>(options =>
    {
        options.ProviderPolicies[AbxModuleRolePermissionValueProvider.ProviderName] = "AbxModuleRole";
        options.ManagementProviders.Add<AbxModuleRolePermissionManagementProvider>();
    });
    
    
  • User Avatar
    0
    alexander.nikonov created

    Oh, was a bit unexpected, but now I understand. I need a "root" permission definition - I cannot assign my permissions straight to the group:

    {
        ...
        var rolesPermission = moduleRoleGroup.AddPermission(ModuleRolePermissions.SubGroupName, L("Permission:ModuleRoles")).WithProviders("MR");
        ...
    }
    
    {
        ...
        options.ProviderPolicies[AbxModuleRolePermissionValueProvider.ProviderName] = "ModuleRoles"; //TODO: Replace with constant ModuleRolePermissions.SubGroupName
        ...
    }
    

    Regarding what you have said in the very beginning:

    You need to cover the role permission provider to load the permissions of the custom role under the role

    do I need to REPLACE some ABP providers (instead of adding my own ones)? What I'm going to do eventually is to replace ABP "Permissions" dialog completely. At the same time, I want to retain as much existing code as possible. I.e. I'm extending Role Management with my two-level role system, but I don't want to break anything which already is functioning at ABP side (if ABP needs traditional approach at some page, it needs to keep functioning).

  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    Ok, you can add your own to do it.

  • User Avatar
    0
    alexander.nikonov created

    I need to filter out only "MR" roles here:

    For this purpose I'm going to useIsModuleRole property:

    Since I want to have it accessible in my claims by the time CheckAsync is called - I need to add this property there somehow. I've found out there are two ways to do that. I've tried both and in both cases the property is successfully added. But later it disappears and the only property I see in Properties is http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/ShortTypeName = role (I don't have idea who adds this, but looks like a default property). So my attempts are below:

    1. Using Contributor:

       public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
       {
           var claimsIdentity = context.ClaimsPrincipal.Identities.First(x => x.AuthenticationType == IdentityAuthenticationType);
      
           var roleClaims = claimsIdentity.FindAll(x => x.Type == AbpClaimTypes.Role).ToArray();
      
           if (roleClaims.Length > 0)
           {
               var moduleRoles = _identityRoleRepository.GetListAsync().Result.Where(x => x.GetProperty("IsModuleRole", false)).Select(x => x.Name);
      
               if (moduleRoles.Any())
               {
                   for (var i = 0; i &lt; roleClaims.Length; i++)
                   {
                       if (moduleRoles.Contains(roleClaims[i].Value))
                       {
                           roleClaims[i].Properties.AddIfNotContains(new System.Collections.Generic.KeyValuePair&lt;string, string&gt;("IsModuleRole", "true")); // I can see the property is present in the claimsIdentity, but in the CheckAsync method - no more...
                       }
                   }
               }
           }
      
           return Task.CompletedTask;
       }
      
    2. Using Factory:

       public class AbxUserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory
       {
           private static string IdentityAuthenticationType => "Identity.Application";
      
           private readonly IIdentityRoleRepository _identityRoleRepository;
      
           public AbxUserClaimsPrincipalFactory
           (           
               UserManager&lt;Volo.Abp.Identity.IdentityUser&gt; userManager,
               RoleManager&lt;Volo.Abp.Identity.IdentityRole&gt; roleManager,
               IOptions&lt;IdentityOptions&gt; options,
               ICurrentPrincipalAccessor currentPrincipalAccessor,
               IAbpClaimsPrincipalFactory abpClaimsPrincipalFactory,
               IIdentityRoleRepository identityRoleRepository
           )
               : base(userManager, roleManager, options, currentPrincipalAccessor, abpClaimsPrincipalFactory)
           {
               _identityRoleRepository = identityRoleRepository;
           }
      
           [UnitOfWork]
           public async override Task&lt;ClaimsPrincipal&gt; CreateAsync(Volo.Abp.Identity.IdentityUser user)
           {
               var principal = await base.CreateAsync(user);
      
               var identity = principal.Identities.First(x => x.AuthenticationType == IdentityAuthenticationType);
      
               var roleClaims = identity.FindAll(x => x.Type == AbpClaimTypes.Role).ToArray();
      
               var moduleRoles = (await _identityRoleRepository.GetListAsync()).Where(x => x.GetProperty("IsModuleRole", false)).Select(x => x.Name);
      
               if (moduleRoles.Any())
               {
                   for (var i = 0; i &lt; roleClaims.Length; i++)
                   {
                       if (moduleRoles.Contains(roleClaims[i].Value))
                       {
                           roleClaims[i].Properties.AddIfNotContains(new System.Collections.Generic.KeyValuePair&lt;string, string&gt;("IsModuleRole", "true")); // I can see the property is present in the claimsIdentity, but in the CheckAsync method - no more...
                       }
                   }
               }
      
               return principal;
           }
       }
      

    Probably here the Properties is occasionally replaced with a new collection?

        public class AbpClaimsMapMiddleware : IMiddleware, ITransientDependency
        {
            public async Task InvokeAsync(HttpContext context, RequestDelegate next)
            {
                var currentPrincipalAccessor = context.RequestServices
                    .GetRequiredService&lt;ICurrentPrincipalAccessor&gt;();
        
                var mapOptions = context.RequestServices
                    .GetRequiredService&lt;IOptions&lt;AbpClaimsMapOptions&gt;>().Value;
        
                var mapClaims = currentPrincipalAccessor
                    .Principal
                    .Claims
                    .Where(claim => mapOptions.Maps.Keys.Contains(claim.Type));
        
                currentPrincipalAccessor
                    .Principal
                    .AddIdentity(
                        new ClaimsIdentity(
                            mapClaims
                                .Select(
                                    claim => new Claim(
                                        mapOptions.Maps[claim.Type](),
                                        claim.Value,
                                        claim.ValueType,
                                        claim.Issuer
                                    )
                                )
                        )
                    );
        
                await next(context);
            }
        }
    
  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    The claim Properties not working with JWT.

    You can try to add new claims:

    foreach(var moduleRole in ModuleRoles)
    {
       identity.AddClaim(new Claim("ModuleRole", moduleRole.Name));
    }
    
  • User Avatar
    0
    alexander.nikonov created

    Thank you. It works.

    I now have the following questions:

    a) After I create "MR" roles on one page - I navigate to the other page, where I am going to assign "MR" roles (= permission definitions with "MR" provider, as we discussed above) to an ordinary role. Alas, I cannot do that until I relogin the user. Do I need to manually add the created role:

                var moduleRole = new IdentityRole(GuidGenerator.Create(), roleName, CurrentTenant.Id)
                {
                    IsDefault = false,
                    IsPublic = false
                };
                moduleRole.ExtraProperties.Add("IsModuleRole", true);
                var newModuleRole = await _identityRoleRepository.InsertAsync(moduleRole, true);
    

    to Definition Store before trying to bind it to an ordinary role (roleName):

       await _permissionAppService.UpdateAsync("MR", roleName, new UpdatePermissionsDto { Permissions = input.Permissions });
    

    ?

    The above is happening because the following method returns null for moduleRole.Name until relogin:

    var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName);
    

    b) I'd like to clarify: in which cases do I need to implement own PermissionManagementProvider? It has the same methods as ValueProviders, CheckAsync...

    c) If I modify the module roles assigned to an ordinary role - I want to modify the corresponding "moduleRole" claims. How and where to do that efficiently (possibly caching instead of pulling from DB each time) without user relogin? I think you might have used similar mechanism already for your data. I'd prefer to update the accessible pages (and APIs) even if the page in the Angular app is reloaded; Please keep in mind, that on one hand - we are talking about ABP roles (which differ from ordinary roles only by extra field), on other hand they are permission definitions for "MR" provider;

    d) will permissionServive.getGrantedPolicy or *abpPermission directive in Angular work for my "MR" permissions in the same way as it work for ordinary "R" permissions?

    Sorry for long posts - I'm trying to find the answers myself, but it's just too much coming up during this development.

  • User Avatar
    0
    liangshiwei created
    Support Team

    a) The above is happening because the following method returns null for moduleRole.Name until relogin: If I modify the module roles assigned to an ordinary role - I want to modify the corresponding "moduleRole" claims. How and where to do that efficiently (possibly caching instead of pulling from DB each time) without user relogin? I think you might have used similar mechanism already for your data. I'd prefer to update the accessible pages (and APIs) even if the page in the Angular app is reloaded; Please keep in mind, that on one hand - we are talking about ABP roles (which differ from ordinary roles only by extra field), on other hand they are permission definitions for "MR" provider;

    Because JWT is immutable, you need to re-login to load the roles. You also can reload the current character for each request via Middleware, for example https://support.abp.io/QA/Questions/2090/How-to-clear-cache-for-features

    b)

    https://docs.abp.io/en/abp/latest/Modules/Permission-Management#permission-management-providers

    IPermissionManager uses these providers when you get/set permissions. You can define your own provider by implementing the IPermissionManagementProvider or inheriting from the PermissionManagementProvider base class.

    IPermissionManager uses permission value providers when you check if permission is granted.

    d) will permissionServive.getGrantedPolicy or *abpPermission directive in Angular work for my "MR" permissions in the same way as it work for ordinary "R" permissions?

    I guess it's ok, the Front-end loads permission grant datas from backend

  • User Avatar
    0
    alexander.nikonov created

    Thank you for the response. We are moving on.

    I'm replacing "Roles" page completely. And here is a strange error. Suddenly I'm getting error on this line:

    await _permissionAppService.UpdateAsync(AbxModuleRolePermissionValueProvider.ProviderName, moduleRole.Name, new UpdatePermissionsDto { Permissions = input.Permissions });
    

    Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown. at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, String policyName) at Volo.Abp.PermissionManagement.PermissionAppService.CheckProviderPolicy(String providerName) at Volo.Abp.PermissionManagement.PermissionAppService.UpdateAsync(String providerName, String providerKey, UpdatePermissionsDto input)

    The same code for RolePermissionValueProvider.ProviderName works fine.

    I'm having all "MR" providers defined: Definition, Management, Value. I had experimental page which used the faulty line and it DID work. Now I can't find anything what could make it stop working and I'm stuck. Do you have suggestions where and what I could check? It looks weird, because permission list is returned properly which means Definition Provider data is OK:

    public class AbxModuleRolePermissionDefinitionProvider : PermissionDefinitionProvider
    {
        public override void Define(IPermissionDefinitionContext context)
        {
            var currentUser = context.ServiceProvider.GetService&lt;ICurrentUser&gt;();
    
            if (currentUser.IsAuthenticated)
            {
                var moduleRoleGroup = context.AddGroup(ModuleRolePermissions.GroupName, L("Permission:ModuleRoleManagement"));
    
                var roleAppService = context.ServiceProvider.GetService&lt;IRoleAppService&gt;();
    
                var moduleRoles = roleAppService.GetModuleRolesAsync(new GetModuleRolesInput()).Result;
    
                var rolesPermission = moduleRoleGroup.AddPermission(ModuleRolePermissions.SubGroupName, L("Permission:ModuleRoles")).WithProviders("MR");
    
                for (var i = 0; i < moduleRoles.Items.Count; i++)
                {
                    rolesPermission.AddChild(moduleRoles.Items[i].Name).WithProviders("MR");
                }
            }
        }
     }
    
  • User Avatar
    0
    liangshiwei created
    Support Team

    I'm replacing "Roles" page completely. And here is a strange error. Suddenly I'm getting error on this line:

    Does the currently logged-in user have the permission?

  • User Avatar
    0
    alexander.nikonov created

    Does the currently logged-in user have the permission?

    Well.. I understand now. No, he does not. But since "MR" are not only permissions for ordinary roles, but also they are ABP roles themselves (just having a special extra properties) - I want them to be always available, like any role (not like permission which must be granted). They are never supposed to be checked as permissions (their permissions are). So how to make them always available?

  • User Avatar
    0
    liangshiwei created
    Support Team

    You can ovveride the PermissionAppService:

    https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Overriding-Services#replacing-an-interface

    public class MyPermissionAppService: PermissionAppService
    {
        ..... CheckProviderPolicy(string providerName)
        {
           if(providerName == xxxx)
           {
              return;
           }
           
          await base.CheckProviderPolicy(providerName);
        }
    }
    
  • User Avatar
    0
    alexander.nikonov created

    I'm completely lost. I've overridden PermissionAppService, but it does not resolve the issue - I'm getting this kind of exception even on "R" provider - now I'm trying to READ permissions of an ordinary role:

    • there is only Authorize attribute decorating this method, no permission at all!

    The exception happens on GetAsync:

        public async Task&lt;PagedResultDto&lt;PermissionGrantInfoDto&gt;> GetPermissionsAsync(GetRolePermissionsInput input)
        {
            var role = await _identityRoleRepository.FindAsync(input.Id, false);
            if (role == null)
            {
                throw new BusinessException(DomainErrorCodes.NotFound, _stringLocalizer.GetString("Roles:RoleNotFound"));
            }
    
            var permissionListResultDto = await _permissionAppService.GetAsync(RolePermissionValueProvider.ProviderName, role.Name); !!!EXCEPTION
    
            var itemsDto = permissionListResultDto.Groups.SelectMany(x => x.Permissions)
                .WhereIf(input.IsGranted.HasValue, x => x.IsGranted == input.IsGranted.Value)
                .WhereIf(!string.IsNullOrWhiteSpace(input.Permission), x => x.Name.IndexOf(input.Permission, StringComparison.OrdinalIgnoreCase) != -1 || x.DisplayName.IndexOf(input.Permission, StringComparison.OrdinalIgnoreCase) != -1);
    
            return new PagedResultDto&lt;PermissionGrantInfoDto&gt;
            {
                TotalCount = itemsDto.Count(),
                Items = itemsDto.ComplexOrderBy(input.Sorting).Skip(input.SkipCount).Take(input.MaxResultCount).ToList()
            };
        }
    

    Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown. at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, String policyName) at Volo.Abp.PermissionManagement.PermissionAppService.CheckProviderPolicy(String providerName) at AbxEps.CentralTools.Permissions.CentralToolsPermissionAppService.CheckProviderPolicy(String providerName) in C:\CT\AbxEps.CentralTools\aspnet-core\src\AbxEps.CentralTools.Application\Permissions\CentralToolsPermissionAppService.cs:line 49 at Volo.Abp.PermissionManagement.PermissionAppService.GetAsync(String providerName, String providerKey)

    Probably it is somehow related to my new custom "Roles" page. When I navigate to it, unlike to other pages, AbxModuleRolePermissionValueProvider => CheckAsync is not triggered. I relogged in, but it did not help. The PermissionProvider seems to be OK, it does contain the required permissions: And the user does contain these permissions:

    BTW, "admin" is a public role from user's department, not a manually assigned. But it should not be difference, right?

  • User Avatar
    0
    liangshiwei created
    Support Team

    I don't know the code details, can you use a new project to reproduce the problem and share it with me? I will check it shiwei.liang@volosoft.com

  • User Avatar
    0
    alexander.nikonov created

    Sorry, cannot prepare the test project which would cover our functionality, it would take too much time.

    I've managed to resolve the permission issue, I guess. Probably it was caused by the scenario when a user has no user roles assigned - only his department's roles... I will get back to this part later probably.

    I guess it's ok, the Front-end loads permission grant datas from backend

    It does not look right now... Please have a look at whole chain:

    a) current user has "Role 1" assigned":

    b) "Role 1" is granted "CT;CTApli:DT~Modify" permission:

    c) Angular app does not see this permission (even though back-end check in the AbxRolePermissionValueProvideris ok - probably there is no direct connection between its result and what getGrantedPolicy returns at client-side) :

  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    You can check the api/abp/application-configuration endpoint.

    It will return information about the current user, permission grant data, etc.

  • User Avatar
    0
    alexander.nikonov created

    There are no "MR" permissions there. I have the idea why. Meanwhile I'm going to create a separate package for optional adding Module Roles functionality to different projects. So the questions are:

    a) Is it possible to have all providers on ONE layer? Because currently they are split between "Domain" and "Application.Contracts" layers following ABP source code structure. Maybe I'm missing something:

    My idea is to enable this functionality in minimum of steps, i.e. just include the package to one layer (project) or to configure it in one place of one project (if possible);

    b) How to filter out this query? I don't want to show "MR" roles here:

  • User Avatar
    0
    liangshiwei created
    Support Team

    A.

    I think there is no problem, but you need to make sure the startup project has its project reference and module dependency, otherwise, the application will not load the permission definitions.

    b

    You can override the repository to filter the roles.

    [ExposeServices(typeof(IIdentityRoleRepository))]
    public class MyEfCoreIdentityRoleRepository : EfCoreIdentityRoleRepository
    {
        public MyEfCoreIdentityRoleRepository(IDbContextProvider<IIdentityDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }
        
        override .....
    }
    
  • User Avatar
    0
    alexander.nikonov created

    You can override the repository to filter the roles.

    This approach does not suit me well. I already use ABP EfCoreIdentityRoleRepository in many places of my solutions. I'd prefer to leave ABP EfCoreIdentityRoleRepository intact, but instead replace client-side ABP IdentityRoleService for specific component(s):

    I've tried to inherit this service, but bumped into the problem: for some reason ABP implementation uses arrow functions instead of prototype-level functions, so I cannot override them in my class:

  • User Avatar
    0
    liangshiwei created
    Support Team

    You can replace the component with yours and use the your own service to get roles. https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement

  • User Avatar
    0
    alexander.nikonov created

    You can replace the component with yours and use the your own service to get roles. https://docs.abp.io/en/abp/latest/UI/Angular/Component-Replacement

    I already use a DepartmentComponent instead of ABP OrganizationUnitsComponent. It generally "mimics" the ABP "Organization Units" component behavior.

    The problem is that when on "Roles" tab you click "Add Role" - modal component OrganizationRolesModalBodyComponent is shown which itself is NOT replaceable. It uses the following service to fill the list of roles:

    The only way to affect this list that I can see it to replace dependency-injected service IdentityRoleService. However, as I have written before, I don't know how to do it properly (if possible).

  • User Avatar
    0
    liangshiwei created
    Support Team

    The only way to affect this list that I can see it to replace dependency-injected service IdentityRoleService. However, as I have written before, I don't know how to do it properly (if possible).

    Yes, you can do it, just:

    [ExposeServices(typeof(IdentityUserAppService))]
    public class MyIdentityRoleAppService : IdentityRoleAppService
    {
        public MyIdentityRoleAppService(IdentityRoleManager roleManager, IIdentityRoleRepository roleRepository, IIdentityClaimTypeRepository identityClaimTypeRepository) : base(roleManager, roleRepository, identityClaimTypeRepository)
        {
        }
    
        public override Task<PagedResultDto<IdentityRoleDto>> GetListAsync(GetIdentityRoleListInput input)
        {
            return base.GetListAsync(input);
        }
    
        public override Task<ListResultDto<IdentityRoleDto>> GetAllListAsync()
        {
            return base.GetAllListAsync();
        }
    }
    
  • User Avatar
    0
    alexander.nikonov created

    Thank you. Overriding AppService is ok too.

    Could you please tell me if it can be considered a bug?

    Why ABP allowed me to create two roles with the same name for null-tenant? ABPROLES does not have constraint for [TENANTID, NAME], but I can't figure it out how to make use of two roles with the same name for the same tenant...

  • User Avatar
    0
    liangshiwei created
    Support Team

    I guess the IsDeleted field value of one of them is true

  • User Avatar
    0
    alexander.nikonov created

    I guess the IsDeleted field value of one of them is true Could be, I've deleted the duplicate and cannot check it out...

    The implementation is almost complete. I have the following question. Let's say my new Role Management page is located in Solution A which has this page in UI. However, I want to assign and revoke granted permissions for other Solutions, each of them has own PermissionDefinition. How to do that? Indeed, Solution A does not have references to another solutions, particularly. it does not have references to Solution B Application Contracts project, where definitions are described. So the "Role Management" page in Solution A does not list the permissions from Solution B and thus cannot assign or revoke them.

  • User Avatar
    0
    liangshiwei created
    Support Team

    See: https://github.com/abpframework/abp/pull/13644

    We added a dynamic permissions system in 7.0, solution A can also load permission definitions without referencing solution B. but they should use the same database.

  • User Avatar
    0
    alexander.nikonov created

    My teammate mentioned that "dynamic permissions" do not fit us for some reasons. I don't know the details yet, I will get back to this later.

    Meanwhile I have the following questions.

    I moved Module Role functionality into a separate solution which needs to be consumed in two different solutions, layer-by-layer: Domain.Shared, Domain, Application.Contracts, Application, EntityFramework Nuget packages, the same way as ABP solution looks like.

    a) ApplicationService layer traditionally contains some localized information:

    public class ModulePermissionAppService : ApplicationService, IModulePermissionAppService
    

    And I need to customize resource localization in the places like this:

    throw new BusinessException(DomainErrorCodes.NotFound, _stringLocalizer.GetString("Roles:RoleNotFound"));
    

    i.e. dependency-injected _stringLocalizer which is IStringLocalizer<SomeResource> needs to have different value in each case. For instance, IStringLocalizer<ResourceA> in one solution and IStringLocalizer<ResourceB> in another solution. How do I do that?

    b) I'd like to pass Authorization Permission class constants in some nice uniform way:

        [Authorize(THIS_NEEDS_TO_BE_CUSTOMIZED.Roles.Modify)] //
        public async Task DeleteRoleAsync(bool isModuleRole, Guid id, bool ignoreDeleted = false)
        
        [Authorize(THIS_NEEDS_TO_BE_CUSTOMIZED.Roles.Read)] //
        public async Task&lt;RoleDto&gt; GetRoleAsync(Guid id)
    
  • User Avatar
    0
    liangshiwei created
    Support Team

    https://docs.abp.io/en/abp/latest/Localization#extending-existing-resource

    You can override existing localized text in different solutions

  • User Avatar
    0
    alexander.nikonov created

    https://docs.abp.io/en/abp/latest/Localization#extending-existing-resource

    You can override existing localized text in different solutions

    Thank you - I will try to make use of the including basic type into any empty resource class of ModulePermission class. Hope it will work out.

    Could you please let me know if it is possible to pass-through additional information of route (like this module ID) from Angular app somehow to a back-end?

    when I am loading the specific page via URL:

    or just navigating to the app https://localhost:4200 (and expecting to see only specific module ID-related pages in the menu)

    inside your method:

    public override async Task&lt;MultiplePermissionGrantResult&gt; CheckAsync(PermissionValuesCheckContext context)
    

    ? I need information about all module IDs (module ID matches Module Role, which contains permissions) for my Angular app pages to check out which of them are to be displayed / hidden.

  • User Avatar
    0
    liangshiwei created
    Support Team

    Hi,

    I think the main question about this ticket has been solved. Could you create a new question for others? Thanks. I'm closing this.

Made with ❤️ on ABP v8.0.0 Updated on September 13, 2023, 07:37