Define claims using the UserClaimsPrincipalFactory
Asked Answered
O

1

10

For several days I try to declare claims for a Blazor application. I finally found a way to do it which is supposed to work but for some reason I can not find my claim in the claims list. I created the following AppClaimsPrincipalFactory:

public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public AppClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
    {
    }
    public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        var id = await GenerateClaimsAsync(user);
        if (user != null)
        {
            id.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName));
        }
        return new ClaimsPrincipal(id);


        var principal = await base.CreateAsync(user);

        if (!string.IsNullOrWhiteSpace(user.FirstName))
        {
            ((ClaimsIdentity)principal.Identity).AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName));
        }

        if (!string.IsNullOrWhiteSpace(user.LastName))
        {
            ((ClaimsIdentity)principal.Identity).AddClaim(new Claim(ClaimTypes.Surname, user.LastName));
        }

        return principal;
    }
}

I added the following code in the ConfigureServices of the Startup.cs file:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();

Can someone help me find what is wrong with my code? Thank you in advance.

UPDATE

Thanks to Brian Parker who paved the way to me. In order to make it work in case someone else needs it, I changed the AppClaimsPrincipalFactory class like this:

public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public AppClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
    {
    }
    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        ClaimsIdentity claims = await base.GenerateClaimsAsync(user);
        claims.AddClaim(new Claim("name", "Aris"));
        claims.AddClaim(new Claim("customClaim", "test value"));
        claims.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName));
        claims.AddClaim(new Claim(ClaimTypes.Surname, user.LastName));
        return claims;
    }
}

I also changed the code services.AddDefaultIdentity in my Startup.cs file:

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddClaimsPrincipalFactory<AppClaimsPrincipalFactory>();

which had as a result to have the following claim values:

name: ["[email protected]","Aris"]
customClaim: test value
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Aristotelis
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname: Pitaridis

Thank you Brian Parker. You made my day.

Olympiaolympiad answered 10/11, 2020 at 22:38 Comment(0)
P
10

Try :

services.AddScoped<AppClaimsPrincipalFactory>();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddClaimsPrincipalFactory<AppClaimsPrincipalFactory>();

services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.IdentityResources["openid"].UserClaims.Add(ClaimTypes.GivenName);
    options.ApiResources.Single().UserClaims.Add(ClaimTypes.GivenName);

    options.IdentityResources["openid"].UserClaims.Add(ClaimTypes.Surname);
    options.ApiResources.Single().UserClaims.Add(ClaimTypes.Surname);

});

Pirogue answered 10/11, 2020 at 23:5 Comment(2)
Thank you. I updated my question in order to help others to solve the same problem. I had to change my AppClaimsPrincipalFactory in order to make it work.Olympiaolympiad
This is still valid now in 2022, using ASP .NET 6.0 with ASP Core Identity. The Claims will always be correct and reloaded automatically (within sliding expiration time and without touching any Identity database tables) for all sign in methods (such as SignInAsync(), PasswordSignInAsync(), even ExternalLoginSignInAsync()) as long as you register a class that inherit from UserClaimsPrincipalFactory in DI like the example above.Insensitive

© 2022 - 2024 — McMap. All rights reserved.