Search code examples
identityabp-frameworkclaims

Custom Claims Principal Factory within ABP


I am using an iDP that provides the username in the 'sub' claim which inside abp does not mark the CurrentUser.IsAuthenticated to true and the id for the user is also null because it is not a GUID. From the documentation I found that you can inherit AbpUserClaimsPrincipalFactory and add your custom claims. I thought I could override the NameIdentifier claim and pull the mapped user from the database and use that GUID custom UserClaimsPrincipalFactory never gets called. Below is my code:

I have tried the below implementation but CreateAsync never gets called.

public class BaselineUserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory
{
    private readonly ICoreApiService _coreApiService;

    public BaselineUserClaimsPrincipalFactory(
           UserManager<IdentityUser> userManager,
           RoleManager<IdentityRole> roleManager,
           IOptions<IdentityOptions> options,
           ICurrentPrincipalAccessor currentPrincipalAccessor,
            IAbpClaimsPrincipalFactory abpClaimsPrincipalFactory,
            ICoreApiService coreApiService)
           : base(
                 userManager,
                 roleManager,
                 options,
                 currentPrincipalAccessor,
                 abpClaimsPrincipalFactory)
    {
        _coreApiService = coreApiService;
    }


    [UnitOfWork]
    public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
    {
        var principal = await base.CreateAsync(user);
        var identity = principal.Identities.First();

        if (identity != null)
        {
             .
             .

            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user_guid));
        }

        return principal;

    }
}

Inside BaselineHttpApiHostModule

public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        PreConfigure<IdentityBuilder>(builder => builder.AddClaimsPrincipalFactory<BaselineUserClaimsPrincipalFactory>());
    }

Solution

  • using IdentityUser = Volo.Abp.Identity.IdentityUser;
    
    public class ServiceClaimTransformation : IClaimsTransformation
    {
        private readonly UserManager<IdentityUser> _userManager;
    
        public ServiceClaimTransformation(UserManager<IdentityUser> userManager)
        {
            _userManager = userManager;
        }
    
        public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            var identity = principal.Identities.FirstOrDefault();
    
            if (identity != null)
            {
                var usernameClaim = identity.Claims.FirstOrDefault(t => t.Type == ClaimTypes.NameIdentifier);
                if (usernameClaim != null)
                {
                    var dbUser = await _userManager.FindByNameAsync(usernameClaim.Value);
                    if (dbUser != null)
                    {
                        identity.RemoveClaim(usernameClaim);
                        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, dbUser.Id.ToString()));
                    }
                }
            }
    
            return principal;
        }
    }
    

    Above is what I ended up doing. This will find the user within the db by username and add their user id to the claims. Below is how you would register in your startup.

    context.Services.AddTransient<IClaimsTransformation, ServiceClaimTransformation>();