JensB
JensB

Reputation: 6850

Adding and accessing claims in asp net core 3.0 using built in Identity server

I'm currently failing at wrapping my head around claims. I have a ASP.Net Core 3 project with the angular template and users stored in app.

I want to add claims to my users, reading up on I thought it would be easy, just add something along the lines of

await _UserManager.AddClaimAsync(user, new Claim(AccountStatic.ClaimTypes._Claim_Id, user.Id));

When you create the user, and then get it back using the below line once they are logged in again:

User.FindFirst(AccountStatic.ClaimTypes._Claim_Id)?.Value;

This does however not work. I can see the claims being written to AspNetUserClaims table in my database but it's not there in the users claims when they log in. There are a few other claims there, but not the ones I have added.

Do I need to define somewhere which of the users claims get included when they log in?

Edit. I found a post stating that I need to add claims using a DI AddClaimsPrincipalFactory. So I added this class.

public class UserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public UserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager,IOptions<IdentityOptions> optionsAccessor): base(userManager, optionsAccessor)
    {}

    //https://levelup.gitconnected.com/add-extra-user-claims-in-asp-net-core-web-applications-1f28c98c9ec6
    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        var identity = await base.GenerateClaimsAsync(user);
        identity.AddClaim(new Claim(AccountStatic.ClaimTypes.Claim_Id, user.Id ?? "[no id]"));
        return identity;
    }
}

And if I step through the code I can see the claims being added here. But in the Controller my custom claims are not present.

internal string GetUserId()
{
    if (User.Identity.IsAuthenticated == false)
        return null;

    return User.FindFirst(AccountStatic.ClaimTypes.Claim_Id)?.Value;
}

Update. Ok I find this very strange. I have been trying to do what others claim work but for me nothing gets me the users name or id. inspecting the User I get the following. Nothing here contains any reference to the logged in user.

enter image description here

Update 2: Just noticed that there is actually an Id in there: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: ed107a11-6c62-496b-901e-ed9e6497662a} Seems to be the users id from the database. Not sure how to access it yet though.

These return null.

User.FindFirst(JwtRegisteredClaimNames.NameId)?.Value;
User.FindFirst("nameidentifier")?.Value;
User.FindFirst("NameIdentifier")?.Value;

Another update I'm using a UserClaimsPrincipalFactory and breakingpointing it and looking at the Claims I can see that all of the ones I want are there. But again, these are not available in my API controllers as seen in the first picture. enter image description here

Upvotes: 3

Views: 4021

Answers (1)

JensB
JensB

Reputation: 6850

I finally understood the problem, in large parts thanks to Ruard van Elburgs comments, and the answer he made in the linked question IdentityServer4 Role Based Authorization.

The problem is that the claims are not added to the access token. There are two tokens, the access token and the identity token. - Ruard van Elburg

They key to understanding what was going on was finding out that there are two tokens, and that they contain different claims and have different purposes.

You can force claims from one token to also be included in the other if you deem it necessary.

The solution to my problem was to add this in Startup.ConfigureServices

services
    .AddIdentityServer(options => {})
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
    {
        foreach (var c in options.ApiResources)
        {
            // the string name of the token I want to include
            c.UserClaims.Add(AccountStatic.ClaimTypes.Claim_Id); 
        }
    });

I still have not figured out how to get the Identity token, but as I'm now including the user Id in the access token my problems are solved for the moment.

Upvotes: 4

Related Questions