ASP.NET Core 2.0.3 ClaimsTransformer in combination with HttpContextAccessor, claims are being cleared

Viewed 3342

In my Asp.Net Core application I want to add custom claims to my ClaimsIdentity so I can access these in different layers of my application. To achieve this I added following code

Startup

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddTransient<IPrincipal>(
            provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
        services.AddTransient<IClaimsTransformation, ClaimsTransformer>();

ClaimsTransformer

public class ClaimsTransformer : IClaimsTransformation
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IPrincipal _principal;
    public ClaimsTransformer(IUnitOfWork unitOfWork, IPrincipal principal)
    {
        _unitOfWork = unitOfWork;
        _principal = principal;
    }
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var currentPrincipal  = (ClaimsIdentity)_principal.Identity;
        var identity = (ClaimsIdentity)principal.Identity;
        if (currentPrincipal.Claims.All(p => p.Type != "UserId"))
        {
            var person = _unitOfWork.PersonRepository.GetPersonBySubjectId(principal.Claims.First(p => p.Type == "sub").Value);
            person.Wait();
            if (person.Result != null)
            {
                currentPrincipal.AddClaim(new Claim("UserId", person.Result.Id.ToString()));
                currentPrincipal.AddClaim(new Claim("TenantId", person.Result.PersonTeams.FirstOrDefault(p => p.Team.TeamType == TeamType.OrganizationTeam)?.Team.OrganizationId.ToString()));
                if (principal.Claims.Any(p => p.Type == "Admin"))
                {
                    currentPrincipal.AddClaim(new Claim("Admin", "True"));
                }
            }
            foreach (var claim in identity.Claims)
            {
                currentPrincipal.AddClaim(claim);
            }
        }
        return Task.FromResult(principal);
    }
}

What I don't understand is, when I run my Claimstransformation and I step through the code, all the needed claims are available, but when I inject my IPrincipal into a custom class, the claims collection is empty, when I don't use the ClaimsTransformation, the claims are available via the injected IPrincipal.

To resolve this issue, I add my IPrincipal to the ClaimsTransformer and duplicate the claims from the TransformAsync input parameter and add the UserId and TenantId. This works, but the problem I have is that I don't understand why the Claims are being deleted when I run the ClaimsTransformer and why I need to add this hack

1 Answers
Related