Activities of "alexander.nikonov"

Hi. My question is related to your reply. Please provide the link / instruction how to apply 7.0 patch. I may reopen my ticket if it matters.

How to apply this patch and where to find it? This is what I have found on github:

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 < roleClaims.Length; i++)
                 {
                     if (moduleRoles.Contains(roleClaims[i].Value))
                     {
                         roleClaims[i].Properties.AddIfNotContains(new System.Collections.Generic.KeyValuePair<string, string>("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<Volo.Abp.Identity.IdentityUser> userManager,
             RoleManager<Volo.Abp.Identity.IdentityRole> roleManager,
             IOptions<IdentityOptions> options,
             ICurrentPrincipalAccessor currentPrincipalAccessor,
             IAbpClaimsPrincipalFactory abpClaimsPrincipalFactory,
             IIdentityRoleRepository identityRoleRepository
         )
             : base(userManager, roleManager, options, currentPrincipalAccessor, abpClaimsPrincipalFactory)
         {
             _identityRoleRepository = identityRoleRepository;
         }
    
         [UnitOfWork]
         public async override Task<ClaimsPrincipal> 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 < roleClaims.Length; i++)
                 {
                     if (moduleRoles.Contains(roleClaims[i].Value))
                     {
                         roleClaims[i].Properties.AddIfNotContains(new System.Collections.Generic.KeyValuePair<string, string>("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<ICurrentPrincipalAccessor>();
    
            var mapOptions = context.RequestServices
                .GetRequiredService<IOptions<AbpClaimsMapOptions>>().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);
        }
    }

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).

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.

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'

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:

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

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...

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.

Showing 161 to 170 of 318 entries
Made with ❤️ on ABP v9.0.0-preview Updated on September 20, 2024, 08:30